package logger import ( "context" "log/slog" "os" "strings" ) type ctxKey struct{} // L 全局 logger,Init 之前使用默认 text 输出。 var L *slog.Logger func init() { L = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug})) } // Init 初始化全局 logger。 // level: debug / info / warn / error // format: text / json func Init(level, format string) { var lvl slog.Level switch strings.ToLower(level) { case "debug": lvl = slog.LevelDebug case "warn": lvl = slog.LevelWarn case "error": lvl = slog.LevelError default: lvl = slog.LevelInfo } opts := &slog.HandlerOptions{Level: lvl} var h slog.Handler switch strings.ToLower(format) { case "json": h = slog.NewJSONHandler(os.Stdout, opts) default: h = slog.NewTextHandler(os.Stdout, opts) } L = slog.New(h) slog.SetDefault(L) } // With 创建带附加字段的 logger。 func With(args ...any) *slog.Logger { return L.With(args...) } // IntoCtx 将 logger 存入 context。 func IntoCtx(ctx context.Context, l *slog.Logger) context.Context { return context.WithValue(ctx, ctxKey{}, l) } // FromCtx 从 context 取出 logger,不存在时返回全局 L。 func FromCtx(ctx context.Context) *slog.Logger { if l, ok := ctx.Value(ctxKey{}).(*slog.Logger); ok { return l } return L } // WithRequestID 创建带 request_id 的 logger 并存入 context。 func WithRequestID(ctx context.Context, requestID string) (context.Context, *slog.Logger) { l := L.With("request_id", requestID) return IntoCtx(ctx, l), l }