Files

78 lines
2.2 KiB
Go

package logfilter
import (
"context"
"log/slog"
"strings"
"sync/atomic"
)
// Handler wraps an slog.Handler and drops records whose message starts
// with any of the configured quiet prefixes (e.g. "metadata:").
//
// The prefix list is shared through an atomic pointer so SetQuiet applies
// to every clone produced by WithAttrs/WithGroup, and is safe to call
// concurrently with logging.
type Handler struct {
inner slog.Handler
prefixes *atomic.Pointer[[]string]
}
// New returns a Handler that delegates to inner but silences messages
// matching any prefix in quietCSV (comma-separated, e.g. "metadata,scanner").
// A colon+space is appended automatically: "metadata" silences "metadata: ...".
// The Handler is always returned (even for an empty quietCSV) so the quiet
// list can be changed later via SetQuiet.
func New(inner slog.Handler, quietCSV string) *Handler {
prefixes := &atomic.Pointer[[]string]{}
parsed := parseQuiet(quietCSV)
prefixes.Store(&parsed)
return &Handler{inner: inner, prefixes: prefixes}
}
// SetQuiet replaces the quiet prefix list. It applies immediately to this
// handler and every WithAttrs/WithGroup clone derived from it.
func (h *Handler) SetQuiet(quietCSV string) {
parsed := parseQuiet(quietCSV)
h.prefixes.Store(&parsed)
}
func parseQuiet(quietCSV string) []string {
trimmed := strings.TrimSpace(quietCSV)
if trimmed == "" {
return nil
}
parts := strings.Split(trimmed, ",")
prefixes := make([]string, 0, len(parts))
for _, p := range parts {
p = strings.TrimSpace(p)
p = strings.TrimSuffix(p, ":")
if p != "" {
prefixes = append(prefixes, p+":")
}
}
return prefixes
}
func (h *Handler) Enabled(ctx context.Context, level slog.Level) bool {
return h.inner.Enabled(ctx, level)
}
func (h *Handler) Handle(ctx context.Context, r slog.Record) error {
msg := r.Message
for _, prefix := range *h.prefixes.Load() {
if strings.HasPrefix(msg, prefix) {
return nil
}
}
return h.inner.Handle(ctx, r)
}
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &Handler{inner: h.inner.WithAttrs(attrs), prefixes: h.prefixes}
}
func (h *Handler) WithGroup(name string) slog.Handler {
return &Handler{inner: h.inner.WithGroup(name), prefixes: h.prefixes}
}