package main import ( "context" "errors" "log/slog" "slices" ) // slogMultiHandler is a simple slog.Handler that passes slog.Records on to // every inner slog.Handler of the slice. type slogMultiHandler []slog.Handler func (smh slogMultiHandler) Enabled(ctx context.Context, level slog.Level) bool { for _, h := range smh { if h.Enabled(ctx, level) { return true } } return false } func (smh slogMultiHandler) Handle(ctx context.Context, record slog.Record) error { retValues := make([]error, len(smh)) for i, h := range smh { if !h.Enabled(ctx, record.Level) { continue } retValues[i] = h.Handle(ctx, record) } return errors.Join(retValues...) } func (smh slogMultiHandler) WithAttrs(attrs []slog.Attr) slog.Handler { newHandlers := make([]slog.Handler, len(smh)) for i, h := range smh { // From slog.Handler.WithAttrs godoc: // "The Handler owns the slice: it may retain, modify or discard it." // Clone the slice so that modifications don't impact other slog.Handlers. newHandlers[i] = h.WithAttrs(slices.Clone(attrs)) } return slogMultiHandler(newHandlers) } func (smh slogMultiHandler) WithGroup(name string) slog.Handler { newHandlers := make([]slog.Handler, len(smh)) for i, h := range smh { newHandlers[i] = h.WithGroup(name) } return slogMultiHandler(newHandlers) }