Documentation ¶
Overview ¶
Package slogx contains extensions for log/slog.
Index ¶
- Constants
- func ChainReplaceAttr(fs ...func([]string, slog.Attr) slog.Attr) func([]string, slog.Attr) slog.Attr
- func ContextWithAttrs(ctx context.Context, attrs ...any) context.Context
- func ContextWithGroup(ctx context.Context, group string) context.Context
- func HandlerFromContext(ctx context.Context) slog.Handler
- func LaxCtxHandler() ctxHandlerOption
- func LogAttrsSkip(ctx context.Context, skip int, handler slog.Handler, level slog.Level, ...)
- func LogSkip(ctx context.Context, skip int, handler slog.Handler, level slog.Level, ...)
- func LoggerFromContext(ctx context.Context) *slog.Logger
- func NewContextWithHandler(ctx context.Context, handler slog.Handler) context.Context
- func NewContextWithLogger(ctx context.Context, log *slog.Logger) context.Context
- func ParseLevel(levelName string) slog.Level
- func SetDefaultCtxHandler(ctx context.Context, fallback slog.Handler, opts ...ctxHandlerOption) context.Context
- func Stack() slog.Attr
- type CtxHandler
Constants ¶
const KeyStack = "stack"
Variables ¶
This section is empty.
Functions ¶
func ChainReplaceAttr ¶
func ContextWithAttrs ¶
ContextWithAttrs applies attrs to a handler stored in ctx.
func ContextWithGroup ¶
ContextWithGroup applies group to a handler stored in ctx.
func HandlerFromContext ¶
HandlerFromContext returns a Handler value stored in ctx if exists or nil.
func LaxCtxHandler ¶
func LaxCtxHandler() ctxHandlerOption
LaxCtxHandler is an option for disable adding !BADCTX attr.
func LogAttrsSkip ¶
func LogAttrsSkip(ctx context.Context, skip int, handler slog.Handler, level slog.Level, msg string, attrs ...slog.Attr)
LogAttrsSkip emits a log record using handler with the current time and the given level and message. Value skip=0 works exactly like (*slog.Logger).LogAttrs, value skip=1 skips caller of LogAttrsSkip() etc.
func LogSkip ¶
func LogSkip(ctx context.Context, skip int, handler slog.Handler, level slog.Level, msg string, args ...any)
LogSkip emits a log record using handler with the current time and the given level and message. Value skip=0 works exactly like (*slog.Logger).Log, value skip=1 skips caller of LogSkip() etc.
func LoggerFromContext ¶
LoggerFromContext returns a Logger value stored in ctx if exists or nil.
func NewContextWithHandler ¶
NewContextWithHandler returns a new Context that carries value handler.
func NewContextWithLogger ¶
NewContextWithLogger returns a new Context that carries value log.
func ParseLevel ¶
ParseLevel converts log level name into slog.Level. It is case insensitive, ignores surrounding spaces and accepts shortened level name. In case of unknown log level name it will return slog.LevelDebug.
Types ¶
type CtxHandler ¶
type CtxHandler struct {
// contains filtered or unexported fields
}
CtxHandler provides a way to use slog.Handler stored in a context instead of slog.Logger. This makes possible to store extra slog.Attr inside a context and make it magically work without needs to get slog.Logger out of context each time you need to log something.
CtxHandler should be used as a default logger's handler. So it's useful only for applications but not libraries - libraries shouldn't expect concrete configuration of default logger and can't expect availability of CtxHandler's features.
Usually when we need a context-specific logging we have to store pre-configured logger inside a context. But then everywhere we need to log something we have to get logger from context first, which is annoying. Also it means we have to use own logger instance and unable to use global logger and log using functions like slog.InfoContext. Example:
func main() { log := slog.New(slog.NewJSONHandler(os.Stdout, nil)) slog.SetDefault(log) // ... srv := &http.Server{ //... } srv.ListenAndServe() log.Info("done") } func (handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() log := slog.With("remote_addr", r.RemoteAddr) ctx = slogx.NewContextWithLogger(ctx, log) handleRequest(ctx) } func handleRequest(ctx context.Context) { log := slogx.LoggerFromContext(ctx) // <-- THIS LINE IS EVERYWHERE! log.Info("message") // Will also log "remote_addr" attribute. }
With CtxHandler same functionality became:
func main() { handler := slog.NewJSONHandler(os.Stdout, nil) ctx := slogx.SetDefaultCtxHandler(context.Background(), handler) // ... srv := &http.Server{ BaseContext: func(net.Listener) context.Context { return ctx }, //... } srv.ListenAndServe() slog.InfoContext(ctx, "done") } func (handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() ctx = slogx.ContextWithAttrs(ctx, "remote_addr", r.RemoteAddr) handleRequest(ctx) } func handleRequest(ctx context.Context) { slog.InfoContext(ctx, "message") // Will also log "remote_addr" attribute. }
Code not aware about CtxHandler (e.g. libraries) will continue to work correctly, but there are some extra restrictions:
- You should not modify default logger after initial configuration.
- If you'll create new logger instance (e.g. using slog.With(...)) then you should not modify Attrs or Group inside ctx while using that logger instance.
Non-Context functions like slog.Info() will work, but they will ignore Attr/Group configured inside ctx.
By default CtxHandler will add attr with key "!BADCTX" and value ctx if ctx does not contain slog handler, but this can be disabled using LaxCtxHandler option.
func (*CtxHandler) Enabled ¶
Enabled implements slog.Handler interface. It uses handler returned by HandlerFromContext or fallback handler.
func (*CtxHandler) Handle ¶
Handle implements slog.Handler interface. It uses handler returned by HandlerFromContext or fallback handler. Adds !BADCTX attr if HandlerFromContext returns nil. Use LaxCtxHandler to disable this behaviour.