Viewing:
package logging
import (
"context"
"log/slog"
"net/http"
"os"
"time"
)
type logKeyType struct{}
var logKey = logKeyType{}
func FromReq(r *http.Request) *slog.Logger {
return FromCtx(r.Context())
}
func ToReq(r *http.Request, newLog *slog.Logger) *http.Request {
return r.WithContext(context.WithValue(r.Context(), logKey, newLog))
}
func FromCtx(c context.Context) *slog.Logger {
val := c.Value(logKey)
log, ok := val.(*slog.Logger)
if !ok {
log = New()
log.Warn("Log not configured. Likely a code error.")
}
return log
}
func replaceLogAttrs(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey && len(groups) == 0 {
return slog.Int64("at", a.Value.Any().(time.Time).UnixMilli())
}
if a.Key == slog.LevelKey && len(groups) == 0 {
lvl := a.Value.Any().(slog.Level)
lvlStr := lvl.String()
switch lvl {
case slog.LevelDebug:
lvlStr = "D"
case slog.LevelInfo:
lvlStr = "I"
case slog.LevelWarn:
lvlStr = "W"
case slog.LevelError:
lvlStr = "E"
}
return slog.String("lvl", lvlStr)
}
return a
}
func New() *slog.Logger {
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{ReplaceAttr: replaceLogAttrs}))
return logger
}
func InjectHttp(l *slog.Logger, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, ToReq(r, l))
})
}