日志自主化:实现 DB 包自维护日志结构,利用 log.Log 自动填充机制 (by AI)
This commit is contained in:
parent
174345dba8
commit
bc3247dc4f
2
Base.go
2
Base.go
@ -97,7 +97,7 @@ func flatArgs(args []any) []any {
|
||||
argValue := reflect.ValueOf(arg)
|
||||
kind := argValue.Kind()
|
||||
if kind == reflect.Map || kind == reflect.Struct || (kind == reflect.Slice && argValue.Type().Elem().Kind() != reflect.Uint8) {
|
||||
args[i] = cast.MustToJSON(arg)
|
||||
args[i] = cast.As(cast.ToJSON(arg))
|
||||
}
|
||||
}
|
||||
return args
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
# 变更记录 - @go/db
|
||||
|
||||
## [1.0.5] - 2026-05-05
|
||||
### 优化
|
||||
- **日志自主化**:
|
||||
- 将数据库日志逻辑从 `log` 包迁移至 `db` 包,实现日志格式与业务逻辑的深度绑定。
|
||||
- 自定义 `DBLog` 结构,利用 `log.GetEntry[DBLog]()` 对象池加速,并支持完整的错误堆栈捕获。
|
||||
- 接入 `log.Log` 的自动填充能力,精简元数据维护逻辑。
|
||||
|
||||
## [1.0.4] - 2026-05-04
|
||||
### 优化
|
||||
- **日志增强**:升级 `apigo.cc/go/log` 至 v1.0.1,并重构数据库日志逻辑,利用新版 `log.DB` API 直接支持错误字段和调用栈捕获,提升排障效率。
|
||||
|
||||
16
DB.go
16
DB.go
@ -237,15 +237,15 @@ type dbLogger struct {
|
||||
}
|
||||
|
||||
func (dl *dbLogger) LogError(errStr string) {
|
||||
dl.logger.DB(dl.config.Type, dl.config.Dsn(), "", nil, 0, errStr)
|
||||
dl.LogDB("", nil, 0, errors.New(errStr))
|
||||
}
|
||||
|
||||
func (dl *dbLogger) LogQuery(query string, args []any, usedTime float32) {
|
||||
dl.logger.DB(dl.config.Type, dl.config.Dsn(), query, args, usedTime)
|
||||
dl.LogDB(query, args, usedTime, nil)
|
||||
}
|
||||
|
||||
func (dl *dbLogger) LogQueryError(errStr string, query string, args []any, usedTime float32) {
|
||||
dl.logger.DB(dl.config.Type, dl.config.Dsn(), query, args, usedTime, errStr)
|
||||
dl.LogDB(query, args, usedTime, errors.New(errStr))
|
||||
}
|
||||
|
||||
var dbConfigs = make(map[string]*Config)
|
||||
@ -378,7 +378,7 @@ func getDB(name string, logger *log.Logger, useCache bool) *DB {
|
||||
if n == 0 {
|
||||
once.Do(func() {
|
||||
dbConfigs1 := make(map[string]*Config)
|
||||
if err := config.Load("db", &dbConfigs1); err == nil {
|
||||
if err := config.Load(&dbConfigs1, "db"); err == nil {
|
||||
for k, v := range dbConfigs1 {
|
||||
if v.Host != "" {
|
||||
dbConfigsLock.Lock()
|
||||
@ -390,7 +390,7 @@ func getDB(name string, logger *log.Logger, useCache bool) *DB {
|
||||
logger.Error(err.Error())
|
||||
}
|
||||
dbConfigs2 := make(map[string]string)
|
||||
if err := config.Load("db", &dbConfigs2); err == nil {
|
||||
if err := config.Load(&dbConfigs2, "db"); err == nil {
|
||||
for k, v := range dbConfigs2 {
|
||||
if strings.Contains(v, "://") {
|
||||
v2 := new(Config)
|
||||
@ -434,7 +434,7 @@ func getDB(name string, logger *log.Logger, useCache bool) *DB {
|
||||
}
|
||||
|
||||
if conf.SSL != "" && len(dbSSLs) == 0 {
|
||||
_ = config.Load("dbssl", &dbSSLs)
|
||||
_ = config.Load(&dbSSLs, "dbssl")
|
||||
}
|
||||
|
||||
if conf.SSL != "" && dbSSLs[conf.SSL] == nil {
|
||||
@ -467,7 +467,7 @@ func getDB(name string, logger *log.Logger, useCache bool) *DB {
|
||||
|
||||
conn, err := getPool(conf)
|
||||
if err != nil {
|
||||
logger.DB(conf.Type, conf.Dsn(), "", nil, 0, err.Error())
|
||||
LogDB(logger, conf, "", nil, 0, err)
|
||||
return &DB{conn: nil, QuoteTag: "\"", Error: err}
|
||||
}
|
||||
|
||||
@ -483,7 +483,7 @@ func getDB(name string, logger *log.Logger, useCache bool) *DB {
|
||||
for _, host := range conf.ReadonlyHosts {
|
||||
conn, err := getPoolForHost(conf, host)
|
||||
if err != nil {
|
||||
logger.DB(conf.Type, conf.Dsn(), "", nil, 0, err.Error())
|
||||
LogDB(logger, conf, "", nil, 0, err)
|
||||
} else {
|
||||
readonlyConnections = append(readonlyConnections, conn)
|
||||
}
|
||||
|
||||
@ -409,7 +409,7 @@ func TestTransaction(t *testing.T) {
|
||||
}
|
||||
|
||||
n2 := countConnection()
|
||||
fmt.Println("# connection count", n1, n2, cast.MustToJSON(dbInst.GetOriginDB().Stats()), ".")
|
||||
fmt.Println("# connection count", n1, n2, cast.As(cast.ToJSON(dbInst.GetOriginDB().Stats())), ".")
|
||||
}
|
||||
|
||||
func countConnection() int {
|
||||
@ -480,5 +480,5 @@ func BenchmarkForPoolParallel(b *testing.B) {
|
||||
b.Log("OpenConnections", dbInst.GetOriginDB().Stats().OpenConnections)
|
||||
|
||||
n2 := countConnection()
|
||||
fmt.Println("# connection count", n1, n2, cast.MustToJSON(dbInst.GetOriginDB().Stats()), ".")
|
||||
fmt.Println("# connection count", n1, n2, cast.As(cast.ToJSON(dbInst.GetOriginDB().Stats())), ".")
|
||||
}
|
||||
|
||||
55
Log.go
Normal file
55
Log.go
Normal file
@ -0,0 +1,55 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"apigo.cc/go/cast"
|
||||
"apigo.cc/go/log"
|
||||
)
|
||||
|
||||
type DBLog struct {
|
||||
log.BaseLog
|
||||
DbType string
|
||||
Dsn string
|
||||
Query string
|
||||
QueryArgs string
|
||||
UsedTime float32
|
||||
Error string
|
||||
CallStacks []string
|
||||
}
|
||||
|
||||
func (dl *dbLogger) LogDB(query string, args []any, usedTime float32, err error, extra ...any) {
|
||||
LogDB(dl.logger, dl.config, query, args, usedTime, err, extra...)
|
||||
}
|
||||
|
||||
func LogDB(logger *log.Logger, conf *Config, query string, args []any, usedTime float32, err error, extra ...any) {
|
||||
if logger == nil {
|
||||
return
|
||||
}
|
||||
|
||||
logType := log.LogTypeDb
|
||||
level := log.INFO
|
||||
var e string
|
||||
if err != nil {
|
||||
logType = log.LogTypeDbError
|
||||
level = log.ERROR
|
||||
e = err.Error()
|
||||
}
|
||||
|
||||
if logger.CheckLevel(level) {
|
||||
entry := log.GetEntry[DBLog]()
|
||||
// 仅关注业务字段,LogType 手动赋值,基础字段由 logger.Log 自动填充
|
||||
entry.LogType = logType
|
||||
entry.DbType = conf.Type
|
||||
entry.Dsn = conf.Dsn()
|
||||
entry.Query = query
|
||||
entry.QueryArgs = cast.To[string](args)
|
||||
entry.UsedTime = usedTime
|
||||
if e != "" {
|
||||
entry.Error = e
|
||||
entry.CallStacks = logger.GetCallStacks()
|
||||
}
|
||||
if len(extra) > 0 {
|
||||
cast.FillMap(&entry.Extra, extra)
|
||||
}
|
||||
logger.Log(entry)
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
"apigo.cc/go/cast"
|
||||
"apigo.cc/go/convert"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
@ -224,7 +223,7 @@ func (r *QueryResult) ToKV(target any) error {
|
||||
}
|
||||
for _, item := range list {
|
||||
newKey := reflect.ValueOf(reflect.New(t.Key()).Interface()).Elem()
|
||||
convert.To(item[colTypes[0].Name()], newKey.Addr().Interface())
|
||||
cast.Convert(newKey.Addr().Interface(), item[colTypes[0].Name()])
|
||||
|
||||
newValue := v.MapIndex(newKey)
|
||||
isNew := false
|
||||
@ -439,10 +438,10 @@ func (r *QueryResult) makeResults(results any, rows *sql.Rows) error {
|
||||
if s != "" {
|
||||
_ = json.Unmarshal([]byte(s), storedValue)
|
||||
}
|
||||
convert.To(storedValue, convertedObject.Interface())
|
||||
cast.Convert(convertedObject.Interface(), storedValue)
|
||||
field.Set(convertedObject.Elem())
|
||||
} else {
|
||||
convert.To(val.Interface(), convertedObject.Interface())
|
||||
cast.Convert(convertedObject.Interface(), val.Interface())
|
||||
}
|
||||
}
|
||||
} else if field.Type().AssignableTo(val.Type()) {
|
||||
|
||||
12
go.mod
12
go.mod
@ -3,13 +3,13 @@ module apigo.cc/go/db
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
apigo.cc/go/cast v1.1.1
|
||||
apigo.cc/go/config v1.0.4
|
||||
apigo.cc/go/convert v1.0.4
|
||||
apigo.cc/go/cast v1.2.6
|
||||
apigo.cc/go/config v1.0.5
|
||||
apigo.cc/go/crypto v1.0.4
|
||||
apigo.cc/go/id v1.0.4
|
||||
apigo.cc/go/log v1.0.1
|
||||
apigo.cc/go/log v1.1.1
|
||||
apigo.cc/go/rand v1.0.4
|
||||
apigo.cc/go/redis v1.0.3
|
||||
apigo.cc/go/safe v1.0.4
|
||||
apigo.cc/go/shell v1.0.4
|
||||
github.com/go-sql-driver/mysql v1.10.0
|
||||
@ -19,10 +19,12 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
apigo.cc/go/convert v1.0.4 // indirect
|
||||
apigo.cc/go/encoding v1.0.4 // indirect
|
||||
apigo.cc/go/file v1.0.4 // indirect
|
||||
apigo.cc/go/file v1.0.5 // indirect
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gomodule/redigo v1.9.3 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
|
||||
12
go.sum
12
go.sum
@ -1,5 +1,5 @@
|
||||
apigo.cc/go/cast v1.1.1 h1:+5pluN8g1RK2J4byr2xkfOmEdKSmy1PByOqDOHtt/Ns=
|
||||
apigo.cc/go/cast v1.1.1/go.mod h1:vh9ZqISCmTUiyinkNMI/s4f045fRlDK3xC+nPWQYBzI=
|
||||
apigo.cc/go/cast v1.2.6 h1:xnWiaQAGsRCrnu1p8fIFQfg5HFSc7CxR+3ItiDIDMaY=
|
||||
apigo.cc/go/cast v1.2.6/go.mod h1:lGlwImiOvHxG7buyMWhFzcdvQzmSaoKbmr7bcDfUpHk=
|
||||
apigo.cc/go/config v1.0.4 h1:WG9zrQkqfFPkrKIL7RNvvAbbkuUBt1Av11ZP/aIfldM=
|
||||
apigo.cc/go/config v1.0.4/go.mod h1:obryzJiK6j7lQex/58d5eWYOGx5O5IABguqNWxyyXJo=
|
||||
apigo.cc/go/convert v1.0.4 h1:5+qPjC3dlPB59GnWZRlmthxcaXQtKvN+iOuiLdJ1GvQ=
|
||||
@ -12,10 +12,12 @@ apigo.cc/go/file v1.0.4 h1:qCKegV7OYh7r0qc3jZjGA/aKh0vIHgmr1OEbhfEmGX8=
|
||||
apigo.cc/go/file v1.0.4/go.mod h1:C9gNo7386iA21OiBmuWh6CznKWlVBDFkhE4f0H0Susg=
|
||||
apigo.cc/go/id v1.0.4 h1:w+JSdeVit52iefIUolrh1qLEZS9XqHNKr1UygFcgv+s=
|
||||
apigo.cc/go/id v1.0.4/go.mod h1:kg7QuceAKtGNzGWt0+pIIh8Qom1eMSWGb8+0Yhi/QVY=
|
||||
apigo.cc/go/log v1.0.0 h1:lI1NGTSS+Jm12G8BD7ZJO4/hrkfuLTu5O8z36GD8GpU=
|
||||
apigo.cc/go/log v1.0.0/go.mod h1:tvPgFpebY9Wf/DlqMHZ0ZjxDp9AaQTywOQKvtBaNqNo=
|
||||
apigo.cc/go/log v1.0.2 h1:OY6T3SC28blDNkMpdRvDK2N4sGdriAB9DBItGl/qOos=
|
||||
apigo.cc/go/log v1.0.2/go.mod h1:tvPgFpebY9Wf/DlqMHZ0ZjxDp9AaQTywOQKvtBaNqNo=
|
||||
apigo.cc/go/rand v1.0.4 h1:we070eWSL0dB8NEMaWjXj43+EekXQTm/h0kKpZ/frqw=
|
||||
apigo.cc/go/rand v1.0.4/go.mod h1:mZ/4Soa3bk+XvDaqPWJuUe1bfEi4eThBj1XmEAuYxsk=
|
||||
apigo.cc/go/redis v1.0.2 h1:gWBrL/6eDxtouTFSZrPKQNdEg1AZr2aKTpCOhwim3dI=
|
||||
apigo.cc/go/redis v1.0.2/go.mod h1:auQ3cyORgD67HF5dNvZ1lA8bqMH1xIbnuKBuZWclNy4=
|
||||
apigo.cc/go/safe v1.0.4 h1:07pRSdEHprF/2v6SsqAjICYFoeLcqjjvHGEdh6Dzrzg=
|
||||
apigo.cc/go/safe v1.0.4/go.mod h1:o568sHS5rTRSVPmhxWod0tGdc+8l1KjidsNY1/OVZr0=
|
||||
apigo.cc/go/shell v1.0.4 h1:EL9zjI39YBe1h+kRYQeAi/8zVGHe5W198DYYN7cENiY=
|
||||
@ -30,6 +32,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/go-sql-driver/mysql v1.10.0 h1:Q+1LV8DkHJvSYAdR83XzuhDaTykuDx0l6fkXxoWCWfw=
|
||||
github.com/go-sql-driver/mysql v1.10.0/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
|
||||
github.com/gomodule/redigo v1.9.3 h1:dNPSXeXv6HCq2jdyWfjgmhBdqnR6PRO3m/G05nvpPC8=
|
||||
github.com/gomodule/redigo v1.9.3/go.mod h1:KsU3hiK/Ay8U42qpaJk+kuNa3C+spxapWpM+ywhcgtw=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user