234 lines
4.3 KiB
Go
234 lines
4.3 KiB
Go
package logger
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"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)
|
|
|
|
// ======================
|
|
// encoder 配置
|
|
// ======================
|
|
|
|
encoderConfig := zapcore.EncoderConfig{
|
|
TimeKey: "time",
|
|
LevelKey: "level",
|
|
MessageKey: "msg",
|
|
CallerKey: "caller",
|
|
EncodeCaller: zapcore.ShortCallerEncoder,
|
|
}
|
|
|
|
// 👉 文件 JSON encoder
|
|
jsonEncoder := zapcore.NewJSONEncoder(func() zapcore.EncoderConfig {
|
|
cfg := encoderConfig
|
|
cfg.EncodeLevel = zapcore.CapitalLevelEncoder
|
|
cfg.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
|
|
return cfg
|
|
}())
|
|
|
|
// 👉 控制台 encoder(可读)
|
|
consoleEncoder := zapcore.NewConsoleEncoder(func() zapcore.EncoderConfig {
|
|
cfg := encoderConfig
|
|
cfg.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
|
cfg.EncodeTime = zapcore.TimeEncoderOfLayout("2006-01-02 15:04:05")
|
|
return cfg
|
|
}())
|
|
|
|
// ======================
|
|
// writer
|
|
// ======================
|
|
|
|
consoleWriter := zapcore.AddSync(os.Stdout)
|
|
infoWriter := getWriter(cfg, "info")
|
|
errorWriter := getWriter(cfg, "error")
|
|
|
|
// ======================
|
|
// core
|
|
// ======================
|
|
|
|
// 控制台(所有级别)
|
|
consoleCore := zapcore.NewCore(
|
|
consoleEncoder,
|
|
consoleWriter,
|
|
level,
|
|
)
|
|
|
|
// info 文件
|
|
infoCore := zapcore.NewCore(
|
|
jsonEncoder,
|
|
infoWriter,
|
|
zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
|
return lvl < zapcore.ErrorLevel && lvl >= level
|
|
}),
|
|
)
|
|
|
|
// error 文件
|
|
errorCore := zapcore.NewCore(
|
|
jsonEncoder,
|
|
errorWriter,
|
|
zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
|
|
return lvl >= zapcore.ErrorLevel
|
|
}),
|
|
)
|
|
|
|
core := zapcore.NewTee(
|
|
consoleCore,
|
|
infoCore,
|
|
errorCore,
|
|
)
|
|
|
|
Log = zap.New(
|
|
core,
|
|
zap.AddCaller(), // 打印调用位置
|
|
zap.AddCallerSkip(1), // 跳过封装层
|
|
)
|
|
}
|
|
|
|
// ======================
|
|
// Daily Writer(按天切割)
|
|
// ======================
|
|
|
|
type DailyWriter struct {
|
|
cfg Config
|
|
level string
|
|
log *lumberjack.Logger
|
|
date string
|
|
}
|
|
|
|
func newDailyWriter(cfg Config, level string) *DailyWriter {
|
|
return &DailyWriter{
|
|
cfg: cfg,
|
|
level: level,
|
|
}
|
|
}
|
|
|
|
func (w *DailyWriter) Write(p []byte) (n int, err error) {
|
|
today := time.Now().Format("2006-01-02")
|
|
|
|
if w.log == nil || w.date != today {
|
|
dir := filepath.Join(w.cfg.Dir, w.level)
|
|
_ = os.MkdirAll(dir, os.ModePerm)
|
|
|
|
filename := filepath.Join(dir, today+".log")
|
|
|
|
w.log = &lumberjack.Logger{
|
|
Filename: filename,
|
|
MaxSize: w.cfg.MaxSize,
|
|
MaxBackups: w.cfg.MaxBackups,
|
|
MaxAge: w.cfg.MaxAge,
|
|
Compress: w.cfg.Compress,
|
|
}
|
|
|
|
w.date = today
|
|
}
|
|
|
|
return w.log.Write(p)
|
|
}
|
|
|
|
func (w *DailyWriter) Sync() error {
|
|
if w.log != nil {
|
|
return w.log.Close()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ======================
|
|
// writer 封装
|
|
// ======================
|
|
|
|
func getWriter(cfg Config, level string) zapcore.WriteSyncer {
|
|
return zapcore.AddSync(newDailyWriter(cfg, level))
|
|
}
|
|
|
|
// ======================
|
|
// 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 支持
|
|
// ======================
|
|
|
|
func SetTraceID(c fiber.Ctx, traceID string) {
|
|
if c == nil {
|
|
return
|
|
}
|
|
|
|
ctx := context.WithValue(c.Context(), TraceIDKey, traceID)
|
|
c.SetContext(ctx)
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
// ======================
|
|
// 优雅退出
|
|
// ======================
|
|
|
|
func Sync() {
|
|
if Log != nil {
|
|
_ = Log.Sync()
|
|
}
|
|
}
|