package logger import ( "context" "fmt" "io" "log/slog" "os" "strings" ) var L *slog.Logger const ( reset = "\033[0m" red = "\033[31m" yellow = "\033[33m" green = "\033[32m" blue = "\033[36m" gray = "\033[90m" ) type consoleHandler struct { w io.Writer colorize bool } func (h *consoleHandler) Enabled(ctx context.Context, level slog.Level) bool { return true } func (h *consoleHandler) Handle(ctx context.Context, r slog.Record) error { level := r.Level.String() color := reset switch r.Level { case slog.LevelError: color = red case slog.LevelWarn: color = yellow case slog.LevelInfo: color = green case slog.LevelDebug: color = gray } var msg string if h.colorize { msg = fmt.Sprintf("%s%s%s %s%s%s %s%s%s", gray, r.Time.Format("15:04:05"), reset, color, level, reset, blue, r.Message, reset) } else { msg = fmt.Sprintf("%s %s %s", r.Time.Format("15:04:05"), level, r.Message) } var pairs []string r.Attrs(func(attr slog.Attr) bool { if h.colorize { pairs = append(pairs, fmt.Sprintf("%s=%v%s", blue, attr.Value, reset)) } else { pairs = append(pairs, fmt.Sprintf("%s=%v", attr.Key, attr.Value)) } return true }) if len(pairs) > 0 { msg += " " + strings.Join(pairs, " ") } fmt.Fprintln(h.w, msg) return nil } func (h *consoleHandler) WithAttrs(attrs []slog.Attr) slog.Handler { return &consoleHandler{w: h.w, colorize: h.colorize} } func (h *consoleHandler) WithGroup(name string) slog.Handler { return &consoleHandler{w: h.w, colorize: h.colorize} } func Init(service string, output io.Writer, level string, colorize bool) { if output == nil { output = os.Stderr } var lvl slog.Level switch level { case "debug": lvl = slog.LevelDebug case "warn": lvl = slog.LevelWarn case "error": lvl = slog.LevelError default: lvl = slog.LevelInfo } if colorize { L = slog.New(&consoleHandler{w: output, colorize: true}).With("service", service, "level", lvl.String()) } else { L = slog.New(slog.NewJSONHandler(output, &slog.HandlerOptions{ Level: lvl, AddSource: false, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey && groups == nil { a.Key = "timestamp" } if a.Key == slog.LevelKey { a.Key = "level" } if a.Key == slog.MessageKey { a.Key = "message" } return a }, })).With("service", service) } } func Info(msg string, args ...any) { if L != nil { L.Info(msg, args...) } } func Warn(msg string, args ...any) { if L != nil { L.Warn(msg, args...) } } func Error(msg string, args ...any) { if L != nil { L.Error(msg, args...) } } func Debug(msg string, args ...any) { if L != nil { L.Debug(msg, args...) } } func With(args ...any) *slog.Logger { if L == nil { return nil } return L.With(args...) }