64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
// 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
|
|
}
|