171 lines
3.3 KiB
Go
171 lines
3.3 KiB
Go
package logger
|
||
|
||
import (
|
||
"context"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
|
||
"github.com/gofiber/fiber/v3"
|
||
"go.uber.org/zap"
|
||
"go.uber.org/zap/zapcore"
|
||
"gopkg.in/natefinch/lumberjack.v2"
|
||
)
|
||
|
||
var Log *zap.Logger
|
||
|
||
const TraceIDKey = "request_id"
|
||
|
||
// ======================
|
||
// 配置结构
|
||
// ======================
|
||
|
||
type Config struct {
|
||
Dir string // 日志目录
|
||
Level string // debug info warn error
|
||
MaxSize int // MB
|
||
MaxBackups int
|
||
MaxAge int // 天
|
||
Compress bool // 是否压缩
|
||
}
|
||
|
||
// ======================
|
||
// 初始化
|
||
// ======================
|
||
|
||
func Init(cfg Config) {
|
||
if cfg.Dir == "" {
|
||
cfg.Dir = "logs"
|
||
}
|
||
|
||
if cfg.Level == "" {
|
||
cfg.Level = "info"
|
||
}
|
||
|
||
level := parseLevel(cfg.Level)
|
||
|
||
encoderConfig := zapcore.EncoderConfig{
|
||
TimeKey: "time",
|
||
LevelKey: "level",
|
||
MessageKey: "msg",
|
||
CallerKey: "caller",
|
||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||
EncodeCaller: zapcore.ShortCallerEncoder,
|
||
}
|
||
|
||
encoder := zapcore.NewJSONEncoder(encoderConfig)
|
||
|
||
// 控制台
|
||
consoleWriter := zapcore.AddSync(os.Stdout)
|
||
|
||
// 文件 writer(info)
|
||
infoWriter := getWriter(cfg, "info")
|
||
|
||
// 文件 writer(error)
|
||
errorWriter := getWriter(cfg, "error")
|
||
|
||
// info core
|
||
infoCore := zapcore.NewCore(
|
||
encoder,
|
||
zapcore.NewMultiWriteSyncer(consoleWriter, infoWriter),
|
||
zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||
return lvl < zapcore.ErrorLevel && lvl >= level
|
||
}),
|
||
)
|
||
|
||
// error core
|
||
errorCore := zapcore.NewCore(
|
||
encoder,
|
||
zapcore.NewMultiWriteSyncer(consoleWriter, errorWriter),
|
||
zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
||
return lvl >= zapcore.ErrorLevel
|
||
}),
|
||
)
|
||
|
||
core := zapcore.NewTee(infoCore, errorCore)
|
||
|
||
Log = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
|
||
}
|
||
|
||
// ======================
|
||
// lumberjack writer
|
||
// ======================
|
||
|
||
func getWriter(cfg Config, level string) zapcore.WriteSyncer {
|
||
dir := filepath.Join(cfg.Dir, level)
|
||
_ = os.MkdirAll(dir, os.ModePerm)
|
||
|
||
return zapcore.AddSync(&lumberjack.Logger{
|
||
Filename: filepath.Join(dir, level+".log"),
|
||
MaxSize: cfg.MaxSize,
|
||
MaxBackups: cfg.MaxBackups,
|
||
MaxAge: cfg.MaxAge,
|
||
Compress: cfg.Compress,
|
||
})
|
||
}
|
||
|
||
// ======================
|
||
// level 解析
|
||
// ======================
|
||
|
||
func parseLevel(lvl string) zapcore.Level {
|
||
switch strings.ToLower(lvl) {
|
||
case "debug":
|
||
return zap.DebugLevel
|
||
case "warn":
|
||
return zap.WarnLevel
|
||
case "error":
|
||
return zap.ErrorLevel
|
||
default:
|
||
return zap.InfoLevel
|
||
}
|
||
}
|
||
|
||
// ======================
|
||
// trace 支持(核心)
|
||
// ======================
|
||
|
||
// Fiber 中使用
|
||
func Ctx(c fiber.Ctx) *zap.Logger {
|
||
if c == nil {
|
||
return Log
|
||
}
|
||
|
||
traceID, _ := c.Locals(TraceIDKey).(string)
|
||
if traceID == "" {
|
||
return Log
|
||
}
|
||
|
||
return Log.With(zap.String("trace_id", traceID))
|
||
}
|
||
|
||
// Service / Repo 使用
|
||
func FromCtx(ctx context.Context) *zap.Logger {
|
||
if ctx == nil {
|
||
return Log
|
||
}
|
||
|
||
traceID, _ := ctx.Value(TraceIDKey).(string)
|
||
if traceID == "" {
|
||
return Log
|
||
}
|
||
|
||
return Log.With(zap.String("trace_id", traceID))
|
||
}
|
||
|
||
// 注入 trace
|
||
func WithTrace(ctx context.Context, traceID string) context.Context {
|
||
return context.WithValue(ctx, TraceIDKey, traceID)
|
||
}
|
||
|
||
// ======================
|
||
// 优雅退出
|
||
// ======================
|
||
|
||
func Sync() {
|
||
if Log != nil {
|
||
_ = Log.Sync()
|
||
}
|
||
}
|