This commit is contained in:
vipg
2026-02-06 16:48:36 +08:00
parent 3b65e135c2
commit 09192205bd
3 changed files with 612 additions and 0 deletions

View File

@@ -0,0 +1,240 @@
// common/logger/logger.go
package logger
import (
"os"
"sync"
"time"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"gopkg.in/natefinch/lumberjack.v2"
)
// 全局单例日志实例
var (
_logger *zap.Logger
once sync.Once
)
// LoggerOptions 日志配置项
type LoggerOptions struct {
Level string // 日志级别debug/info/warn/error/panic/fatal
Format string // 输出格式console控制台/jsonJSON
OutputPath string // 文件输出路径(如./logs/app.log
MaxSize int // 单个日志文件最大大小MB
MaxBackups int // 最大保留日志文件数
MaxAge int // 最大保留天数
Compress bool // 是否压缩日志文件
ShowLine bool // 是否显示代码行号
ConsoleColor bool // 控制台是否显示彩色(开发环境用)
ServiceName string // 服务名多业务时区分日志归属如user/order
StacktraceKey string // 堆栈信息键名
CallerSkip int // 调用栈跳过数(适配封装层,正确显示业务代码行号)
FlushInterval time.Duration // 日志刷盘间隔
}
// LoggerOption 选项模式函数类型
type LoggerOption func(*LoggerOptions)
// defaultLoggerOptions 初始化默认配置
// 开发环境默认控制台彩色日志、info级别、显示行号
func defaultLoggerOptions() *LoggerOptions {
return &LoggerOptions{
Level: "info",
Format: "console",
OutputPath: "./logs/app.log",
MaxSize: 100, // 单个文件100MB
MaxBackups: 10, // 保留10个备份
MaxAge: 7, // 保留7天
Compress: true, // 压缩备份文件
ShowLine: true, // 显示行号
ConsoleColor: true, // 控制台彩色
ServiceName: "trading_assistant", // 默认服务名
StacktraceKey: "stacktrace",
CallerSkip: 1, // 跳过当前封装层,正确显示业务代码行号
FlushInterval: 3 * time.Second,
}
}
// 以下为配置项设置函数,支持链式调用
func WithLevel(level string) LoggerOption {
return func(o *LoggerOptions) { o.Level = level }
}
func WithFormat(format string) LoggerOption {
return func(o *LoggerOptions) { o.Format = format }
}
func WithOutputPath(path string) LoggerOption {
return func(o *LoggerOptions) { o.OutputPath = path }
}
func WithServiceName(name string) LoggerOption {
return func(o *LoggerOptions) { o.ServiceName = name }
}
func WithShowLine(show bool) LoggerOption {
return func(o *LoggerOptions) { o.ShowLine = show }
}
func WithConsoleColor(color bool) LoggerOption {
return func(o *LoggerOptions) { o.ConsoleColor = color }
}
// getZapLevel 转换日志级别为zapcore.Level
func getZapLevel(level string) zapcore.Level {
switch level {
case "debug":
return zapcore.DebugLevel
case "warn":
return zapcore.WarnLevel
case "error":
return zapcore.ErrorLevel
case "panic":
return zapcore.PanicLevel
case "fatal":
return zapcore.FatalLevel
default:
return zapcore.InfoLevel // 默认info级别
}
}
// getEncoder 获取日志编码器console/json
func getEncoder(opts *LoggerOptions) zapcore.Encoder {
// 日志基础配置:时间格式、服务名、调用栈等
encoderConfig := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
NameKey: "service",
CallerKey: "caller",
MessageKey: "msg",
StacktraceKey: opts.StacktraceKey,
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder, // 级别大写INFO/ERROR
EncodeTime: zapcore.RFC3339TimeEncoder, // 时间格式RFC3339
EncodeDuration: zapcore.SecondsDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder, // 调用者格式:文件:行号
}
// 开发环境:控制台彩色编码器
if opts.Format == "console" && opts.ConsoleColor {
return zapcore.NewConsoleEncoder(encoderConfig)
}
// 生产环境JSON编码器便于日志收集分析如ELK
return zapcore.NewJSONEncoder(encoderConfig)
}
// getWriteSyncer 获取日志写入器(文件+控制台)
// 同时输出到文件和控制台,文件自动切割
func getWriteSyncer(opts *LoggerOptions) zapcore.WriteSyncer {
// 日志文件切割配置基于lumberjack
lumberjackLogger := &lumberjack.Logger{
Filename: opts.OutputPath,
MaxSize: opts.MaxSize,
MaxBackups: opts.MaxBackups,
MaxAge: opts.MaxAge,
Compress: opts.Compress,
}
// 同时输出到文件和控制台
return zapcore.NewMultiWriteSyncer(
zapcore.AddSync(os.Stdout),
zapcore.AddSync(lumberjackLogger),
)
}
// InitLogger 初始化全局单例日志实例
func InitLogger(opts ...LoggerOption) *zap.Logger {
once.Do(func() {
// 加载默认配置 + 覆盖用户自定义配置
options := defaultLoggerOptions()
for _, opt := range opts {
opt(options)
}
// 1. 设置日志级别
level := getZapLevel(options.Level)
core := zapcore.NewCore(
getEncoder(options), // 编码器
getWriteSyncer(options), // 写入器
level, // 日志级别
)
// 2. 构建日志实例配置:是否显示调用者、堆栈信息
zapOpts := []zap.Option{zap.AddCallerSkip(options.CallerSkip)}
if options.ShowLine {
zapOpts = append(zapOpts, zap.AddCaller()) // 显示调用者(文件:行号)
}
// 错误级别及以上显示堆栈信息
zapOpts = append(zapOpts, zap.AddStacktrace(zapcore.ErrorLevel))
// 设置服务名
zapOpts = append(zapOpts, zap.Fields(zap.String("service", options.ServiceName)))
// 3. 创建日志实例
_logger = zap.New(core, zapOpts...)
// 4. 定时刷盘(避免日志驻留内存)
go func() {
ticker := time.NewTicker(options.FlushInterval)
defer ticker.Stop()
for range ticker.C {
_ = _logger.Sync()
}
}()
// 5. 应用退出时刷盘
os.Setenv("ZAP_FLUSH_ON_EXIT", "true")
})
return _logger
}
// GetLogger 获取全局单例日志实例
func GetLogger() *zap.Logger {
if _logger == nil {
// 未初始化时,返回默认控制台日志(兜底)
return InitLogger()
}
return _logger
}
// --------------- 轻量封装日志方法 ---------------
// 简化业务层调用无需每次获取logger实例
// 复杂日志如带字段可直接使用GetLogger()获取原生实例
// Debug 调试日志
func Debug(msg string, fields ...zap.Field) {
GetLogger().Debug(msg, fields...)
}
// Info 信息日志
func Info(msg string, fields ...zap.Field) {
GetLogger().Info(msg, fields...)
}
// Warn 警告日志
func Warn(msg string, fields ...zap.Field) {
GetLogger().Warn(msg, fields...)
}
// Error 错误日志(带堆栈)
func Error(msg string, fields ...zap.Field) {
GetLogger().Error(msg, fields...)
}
// Panic 恐慌日志打印后触发panic
func Panic(msg string, fields ...zap.Field) {
GetLogger().Panic(msg, fields...)
}
// Fatal 致命日志(打印后退出程序)
func Fatal(msg string, fields ...zap.Field) {
GetLogger().Fatal(msg, fields...)
}
// Sync 手动刷盘(如重要操作后)
func Sync() error {
return GetLogger().Sync()
}