- NewLogger 工厂函数:支持 JSON/Console 编码、stdout/文件/多输出、lumberjack 轮转 - NewGormLogger 实现 gorm.Interface:Trace 区分错误/慢查询/正常查询 - output_stdout 用 *bool 三态处理(nil=true, true, false) - 默认值:level=info, encoding=json, max_size=100, max_backups=5, max_age=30 - 慢查询阈值 200ms,ErrRecordNotFound 不视为错误 - 编译时接口检查: var _ gormlogger.Interface = (*GormLogger)(nil) - 完整 TDD 测试覆盖 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
94 lines
2.0 KiB
Go
94 lines
2.0 KiB
Go
package logger
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"gcy_hpc_server/internal/config"
|
|
|
|
"go.uber.org/zap"
|
|
"go.uber.org/zap/zapcore"
|
|
"gopkg.in/natefinch/lumberjack.v2"
|
|
)
|
|
|
|
func NewLogger(cfg config.LogConfig) (*zap.Logger, error) {
|
|
level := applyDefault(cfg.Level, "info")
|
|
|
|
var zapLevel zapcore.Level
|
|
if err := zapLevel.UnmarshalText([]byte(level)); err != nil {
|
|
return nil, fmt.Errorf("invalid log level %q: %w", level, err)
|
|
}
|
|
|
|
encoding := applyDefault(cfg.Encoding, "json")
|
|
encoderConfig := zap.NewProductionEncoderConfig()
|
|
encoderConfig.TimeKey = "ts"
|
|
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
|
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
|
|
|
|
var encoder zapcore.Encoder
|
|
switch encoding {
|
|
case "console":
|
|
encoder = zapcore.NewConsoleEncoder(encoderConfig)
|
|
default:
|
|
encoder = zapcore.NewJSONEncoder(encoderConfig)
|
|
}
|
|
|
|
var syncers []zapcore.WriteSyncer
|
|
|
|
stdout := true
|
|
if cfg.OutputStdout != nil {
|
|
stdout = *cfg.OutputStdout
|
|
}
|
|
if stdout {
|
|
syncers = append(syncers, zapcore.AddSync(os.Stdout))
|
|
}
|
|
|
|
if cfg.FilePath != "" {
|
|
maxSize := applyDefaultInt(cfg.MaxSize, 100)
|
|
maxBackups := applyDefaultInt(cfg.MaxBackups, 5)
|
|
maxAge := applyDefaultInt(cfg.MaxAge, 30)
|
|
compress := cfg.Compress || cfg.MaxSize == 0 && cfg.MaxBackups == 0 && cfg.MaxAge == 0
|
|
|
|
lj := &lumberjack.Logger{
|
|
Filename: cfg.FilePath,
|
|
MaxSize: maxSize,
|
|
MaxBackups: maxBackups,
|
|
MaxAge: maxAge,
|
|
Compress: compress,
|
|
}
|
|
syncers = append(syncers, zapcore.AddSync(lj))
|
|
}
|
|
|
|
if len(syncers) == 0 {
|
|
syncers = append(syncers, zapcore.AddSync(os.Stdout))
|
|
}
|
|
|
|
writeSyncer := syncers[0]
|
|
if len(syncers) > 1 {
|
|
writeSyncer = zapcore.NewMultiWriteSyncer(syncers...)
|
|
}
|
|
|
|
core := zapcore.NewCore(encoder, writeSyncer, zapLevel)
|
|
|
|
opts := []zap.Option{
|
|
zap.AddCaller(),
|
|
zap.AddStacktrace(zapcore.ErrorLevel),
|
|
}
|
|
|
|
return zap.New(core, opts...), nil
|
|
}
|
|
|
|
func applyDefault(val, def string) string {
|
|
if val == "" {
|
|
return def
|
|
}
|
|
return val
|
|
}
|
|
|
|
func applyDefaultInt(val, def int) int {
|
|
if val == 0 {
|
|
return def
|
|
}
|
|
return val
|
|
}
|