240 lines
7.0 KiB
Go
240 lines
7.0 KiB
Go
// 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(控制台)/json(JSON)
|
||
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()
|
||
} |