From 8549737a469f09e88031af2c02e82ba823825076 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 22 Aug 2024 17:45:30 +0800 Subject: [PATCH] feat: add async log and update gorm tracing (#149) * feat: add async log and update grom tracing * chore: fix typo --- CHANGELOG.md | 7 +++++- config/docker/database.yaml | 23 ++++++++++--------- config/docker/logger.yaml | 1 + config/local/database.yaml | 46 +++++++++++++++++++------------------ config/local/logger.yaml | 1 + go.mod | 1 + go.sum | 3 +++ pkg/log/config.go | 3 +++ pkg/log/zap.go | 34 +++++++++++++++++++++------ pkg/storage/orm/orm.go | 22 ++++++++---------- 10 files changed, 87 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61c24a7b5..6e56bc39b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ -## Changelog +# Changelog + +## v1.10.0 + +- feat: support async flush log to disk +- chore: using gorm offical plguin for tracing and metrics ## v1.9.0 diff --git a/config/docker/database.yaml b/config/docker/database.yaml index 67321c9cf..c4a934387 100644 --- a/config/docker/database.yaml +++ b/config/docker/database.yaml @@ -1,14 +1,15 @@ default: - Driver: mysql # 驱动名称,目前支持 mysql,postgres,默认: mysql - Name: eagle # 数据库名称 - Addr: db:3306 # 如果是 docker,可以替换为 对应的服务名称,eg: db:3306 + Driver: mysql # 驱动名称,目前支持 mysql,postgres,默认: mysql + Name: eagle # 数据库名称 + Addr: db:3306 # 如果是 docker,可以替换为 对应的服务名称,eg: db:3306 UserName: root Password: root - ShowLog: true # 是否打印所有SQL日志 - MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 - MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 - Timeout: 3s # 数据库连接超时时间 - ReadTimeout: 3s # 数据库去读超时时间, 0代表不限制 - WriteTimeout: 3s # 数据库写入超时时间, 0代表不限制 - ConnMaxLifeTime: 4h # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 - SlowThreshold: 500ms # 慢查询阈值,设置后只打印慢查询日志,默认为200ms + ShowLog: true # 是否打印所有SQL日志 + MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 + MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 + Timeout: 3s # 数据库连接超时时间 + ReadTimeout: 3s # 数据库去读超时时间, 0代表不限制 + WriteTimeout: 3s # 数据库写入超时时间, 0代表不限制 + ConnMaxLifeTime: 4h # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 + SlowThreshold: 500ms # 慢查询阈值,设置后只打印慢查询日志,默认为200ms + EnableTrace: false diff --git a/config/docker/logger.yaml b/config/docker/logger.yaml index 38698a350..0090c7aa6 100644 --- a/config/docker/logger.yaml +++ b/config/docker/logger.yaml @@ -11,3 +11,4 @@ LogRollingPolicy: daily LogRotateDate: 1 LogRotateSize: 1 LogBackupCount: 7 +FlushInterval: 1s diff --git a/config/local/database.yaml b/config/local/database.yaml index 3236984f3..fd9df7546 100644 --- a/config/local/database.yaml +++ b/config/local/database.yaml @@ -1,28 +1,30 @@ default: - Driver: mysql # 驱动名称,目前支持: mysql,postgres,默认: mysql - Name: eagle # 数据库名称 - Addr: localhost:3306 # 如果是 docker,可以替换为 对应的服务名称,eg: db:3306, pg:5432 + Driver: mysql # 驱动名称,目前支持: mysql,postgres,默认: mysql + Name: eagle # 数据库名称 + Addr: localhost:3306 # 如果是 docker,可以替换为 对应的服务名称,eg: db:3306, pg:5432 UserName: root Password: 123456 - ShowLog: true # 是否打印所有SQL日志 - MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 - MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 - Timeout: 3s # 数据库连接超时时间, 如果是 PostgreSQL 不需要加入单位 - ReadTimeout: 3s # 数据库去读超时时间, 0代表不限制,如果是PostgreSQL, 3000代表3s - WriteTimeout: 3s # 数据库写入超时时间, 0代表不限制,如果是PostgreSQL, 不会使用该字段的值 - ConnMaxLifeTime: 4h # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 - SlowThreshold: 500ms # 慢查询阈值,设置后只打印慢查询日志,默认为200ms + ShowLog: true # 是否打印所有SQL日志 + MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 + MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 + Timeout: 3s # 数据库连接超时时间, 如果是 PostgreSQL 不需要加入单位 + ReadTimeout: 3s # 数据库去读超时时间, 0代表不限制,如果是PostgreSQL, 3000代表3s + WriteTimeout: 3s # 数据库写入超时时间, 0代表不限制,如果是PostgreSQL, 不会使用该字段的值 + ConnMaxLifeTime: 4h # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 + SlowThreshold: 500ms # 慢查询阈值,设置后只打印慢查询日志,默认为200ms + EnableTrace: false user: - Driver: mysql # 驱动名称,目前支持: mysql,postgres,默认: mysql - Name: eagle # 数据库名称 - Addr: localhost:3306 # 如果是 docker,可以替换为 对应的服务名称,eg: db:3306, pg:5432 + Driver: mysql # 驱动名称,目前支持: mysql,postgres,默认: mysql + Name: eagle # 数据库名称 + Addr: localhost:3306 # 如果是 docker,可以替换为 对应的服务名称,eg: db:3306, pg:5432 UserName: root Password: 123456 - ShowLog: true # 是否打印所有SQL日志 - MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 - MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 - Timeout: 3s # 数据库连接超时时间 - ReadTimeout: 3s # 数据库去读超时时间, 0代表不限制 - WriteTimeout: 3s # 数据库写入超时时间, 0代表不限制 - ConnMaxLifeTime: 4h # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 - SlowThreshold: 500ms # 慢查询阈值,设置后只打印慢查询日志,默认为200ms + ShowLog: true # 是否打印所有SQL日志 + MaxIdleConn: 10 # 最大闲置的连接数,0意味着使用默认的大小2, 小于0表示不使用连接池 + MaxOpenConn: 60 # 最大打开的连接数, 需要小于数据库配置中的max_connections数 + Timeout: 3s # 数据库连接超时时间 + ReadTimeout: 3s # 数据库去读超时时间, 0代表不限制 + WriteTimeout: 3s # 数据库写入超时时间, 0代表不限制 + ConnMaxLifeTime: 4h # 单个连接最大存活时间,建议设置比数据库超时时长(wait_timeout)稍小一些 + SlowThreshold: 500ms # 慢查询阈值,设置后只打印慢查询日志,默认为200ms + EnableTrace: false diff --git a/config/local/logger.yaml b/config/local/logger.yaml index 38698a350..0090c7aa6 100644 --- a/config/local/logger.yaml +++ b/config/local/logger.yaml @@ -11,3 +11,4 @@ LogRollingPolicy: daily LogRotateDate: 1 LogRotateSize: 1 LogBackupCount: 7 +FlushInterval: 1s diff --git a/go.mod b/go.mod index 795b6336d..fb142853a 100644 --- a/go.mod +++ b/go.mod @@ -203,4 +203,5 @@ require ( gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/plugin/opentelemetry v0.1.4 // indirect ) diff --git a/go.sum b/go.sum index 9242a7c04..72ee4d886 100644 --- a/go.sum +++ b/go.sum @@ -1257,11 +1257,14 @@ gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo= gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0= gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= +gorm.io/driver/sqlite v1.5.0 h1:zKYbzRCpBrT1bNijRnxLDJWPjVfImGEn0lSnUY5gZ+c= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s= gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +gorm.io/plugin/opentelemetry v0.1.4 h1:7p0ocWELjSSRI7NCKPW2mVe6h43YPini99sNJcbsTuc= +gorm.io/plugin/opentelemetry v0.1.4/go.mod h1:tndJHOdvPT0pyGhOb8E2209eXJCUxhC5UpKw7bGVWeI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/pkg/log/config.go b/pkg/log/config.go index 32c88fbf9..f7d0e0b76 100644 --- a/pkg/log/config.go +++ b/pkg/log/config.go @@ -1,5 +1,7 @@ package log +import "time" + // Config log config type Config struct { Development bool @@ -14,4 +16,5 @@ type Config struct { LogFormatText bool LogRollingPolicy string LogBackupCount uint + FlushInterval time.Duration // default is 30s, recommend is dev or test is 1s, prod is 1m } diff --git a/pkg/log/zap.go b/pkg/log/zap.go index 717022c29..21a8471e2 100644 --- a/pkg/log/zap.go +++ b/pkg/log/zap.go @@ -167,19 +167,29 @@ func getAllCore(encoder zapcore.Encoder, cfg *Config) zapcore.Core { allLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl <= zapcore.FatalLevel }) - return zapcore.NewCore(encoder, zapcore.AddSync(allWriter), allLevel) + + asyncWriter := &zapcore.BufferedWriteSyncer{ + WS: zapcore.AddSync(allWriter), + FlushInterval: cfg.FlushInterval, + } + return zapcore.NewCore(encoder, asyncWriter, allLevel) } func getInfoCore(encoder zapcore.Encoder, cfg *Config) zapcore.Core { - infoWrite := getLogWriterWithTime(cfg, GetLogFile(cfg.Filename, logSuffix)) + infoWriter := getLogWriterWithTime(cfg, GetLogFile(cfg.Filename, logSuffix)) infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { return lvl <= zapcore.InfoLevel }) - return zapcore.NewCore(encoder, zapcore.AddSync(infoWrite), infoLevel) + + asyncWriter := &zapcore.BufferedWriteSyncer{ + WS: zapcore.AddSync(infoWriter), + FlushInterval: cfg.FlushInterval, + } + return zapcore.NewCore(encoder, asyncWriter, infoLevel) } func getWarnCore(encoder zapcore.Encoder, cfg *Config) (zapcore.Core, zap.Option) { - warnWrite := getLogWriterWithTime(cfg, GetLogFile(cfg.Filename, warnLogSuffix)) + warnWriter := getLogWriterWithTime(cfg, GetLogFile(cfg.Filename, warnLogSuffix)) var stacktrace zap.Option warnLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { if !cfg.DisableCaller { @@ -189,12 +199,17 @@ func getWarnCore(encoder zapcore.Encoder, cfg *Config) (zapcore.Core, zap.Option } return lvl == zapcore.WarnLevel }) - return zapcore.NewCore(encoder, zapcore.AddSync(warnWrite), warnLevel), stacktrace + + asyncWriter := &zapcore.BufferedWriteSyncer{ + WS: zapcore.AddSync(warnWriter), + FlushInterval: cfg.FlushInterval, + } + return zapcore.NewCore(encoder, asyncWriter, warnLevel), stacktrace } func getErrorCore(encoder zapcore.Encoder, cfg *Config) (zapcore.Core, zap.Option) { errorFilename := GetLogFile(cfg.Filename, errorLogSuffix) - errorWrite := getLogWriterWithTime(cfg, errorFilename) + errorWriter := getLogWriterWithTime(cfg, errorFilename) var stacktrace zap.Option errorLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { if !cfg.DisableCaller { @@ -204,7 +219,12 @@ func getErrorCore(encoder zapcore.Encoder, cfg *Config) (zapcore.Core, zap.Optio } return lvl >= zapcore.ErrorLevel }) - return zapcore.NewCore(encoder, zapcore.AddSync(errorWrite), errorLevel), stacktrace + + asyncWriter := &zapcore.BufferedWriteSyncer{ + WS: zapcore.AddSync(errorWriter), + FlushInterval: cfg.FlushInterval, + } + return zapcore.NewCore(encoder, asyncWriter, errorLevel), stacktrace } // getLogWriterWithTime 按时间(小时)进行切割 diff --git a/pkg/storage/orm/orm.go b/pkg/storage/orm/orm.go index 5b2b8fa7d..3d3539c0e 100644 --- a/pkg/storage/orm/orm.go +++ b/pkg/storage/orm/orm.go @@ -8,16 +8,14 @@ import ( "sync" "time" - "github.com/go-eagle/eagle/pkg/config" - - otelgorm "github.com/1024casts/gorm-opentelemetry" "gorm.io/driver/clickhouse" "gorm.io/driver/mysql" "gorm.io/driver/postgres" - - // GORM MySQL "gorm.io/gorm" "gorm.io/gorm/logger" + "gorm.io/plugin/opentelemetry/tracing" + + "github.com/go-eagle/eagle/pkg/config" ) const ( @@ -54,6 +52,7 @@ type Config struct { WriteTimeout string ConnMaxLifeTime time.Duration SlowThreshold time.Duration // 慢查询时长,默认500ms + EnableTrace bool } // New create a or multi database client @@ -164,15 +163,12 @@ func NewInstance(c *Config) (db *gorm.DB) { db.Set("gorm:table_options", "CHARSET=utf8mb4") - // Initialize otel plugin with options - plugin := otelgorm.NewPlugin( - // include any options here - ) - // set trace - err = db.Use(plugin) - if err != nil { - log.Panicf("using gorm opentelemetry, err: %+v", err) + if c.EnableTrace { + err = db.Use(tracing.NewPlugin()) + if err != nil { + log.Panicf("using gorm opentelemetry, err: %+v", err) + } } return db