// Package logging configures the structured JSON logger used across the service. package logging import ( "context" "log/slog" "os" ) type ctxKey int const requestIDKey ctxKey = iota // New returns a slog.Logger that writes JSON to stdout at the given level. // Valid levels: "debug", "info", "warn", "error". Unknown levels default to info. func New(level string) *slog.Logger { 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 } handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ Level: lvl, ReplaceAttr: func(_ []string, a slog.Attr) slog.Attr { if a.Key == slog.TimeKey { return slog.Attr{Key: "time", Value: a.Value} } if a.Key == slog.MessageKey { return slog.Attr{Key: "event", Value: a.Value} } return a }, }) return slog.New(handler) } // WithRequestID stores the request ID in the context for downstream loggers. func WithRequestID(ctx context.Context, id string) context.Context { return context.WithValue(ctx, requestIDKey, id) } // RequestIDFrom returns the request ID stored in ctx, or empty string if absent. func RequestIDFrom(ctx context.Context) string { if v, ok := ctx.Value(requestIDKey).(string); ok { return v } return "" } // FromContext returns a logger pre-bound with the request_id from ctx (if any). func FromContext(ctx context.Context, base *slog.Logger) *slog.Logger { if id := RequestIDFrom(ctx); id != "" { return base.With("request_id", id) } return base }