log: use sync map

This commit is contained in:
MariusVanDerWijden 2025-05-29 11:21:13 +02:00 committed by lightclient
parent 64773bf6bc
commit 4fb7b3a24e

View file

@ -21,7 +21,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
"maps"
"regexp" "regexp"
"runtime" "runtime"
"strconv" "strconv"
@ -42,18 +41,17 @@ type GlogHandler struct {
level atomic.Int32 // Current log level, atomically accessible level atomic.Int32 // Current log level, atomically accessible
override atomic.Bool // Flag whether overrides are used, atomically accessible override atomic.Bool // Flag whether overrides are used, atomically accessible
patterns []pattern // Current list of patterns to override with patterns []pattern // Current list of patterns to override with
siteCache map[uintptr]slog.Level // Cache of callsite pattern evaluations siteCache sync.Map // Cache of callsite pattern evaluations, maps uintptr -> slog.Level
location string // file:line location where to do a stackdump at location string // file:line location where to do a stackdump at
lock sync.RWMutex // Lock protecting the override pattern list lock sync.RWMutex // Lock protecting the override pattern list
} }
// NewGlogHandler creates a new log handler with filtering functionality similar // NewGlogHandler creates a new log handler with filtering functionality similar
// to Google's glog logger. The returned handler implements Handler. // to Google's glog logger. The returned handler implements Handler.
func NewGlogHandler(h slog.Handler) *GlogHandler { func NewGlogHandler(h slog.Handler) *GlogHandler {
return &GlogHandler{ return &GlogHandler{
origin: h, origin: h,
siteCache: make(map[uintptr]slog.Level),
} }
} }
@ -69,7 +67,7 @@ type pattern struct {
func (h *GlogHandler) Verbosity(level slog.Level) { func (h *GlogHandler) Verbosity(level slog.Level) {
h.level.Store(int32(level)) h.level.Store(int32(level))
// clear the cache to make sure the verbosity is applied correctly. // clear the cache to make sure the verbosity is applied correctly.
h.siteCache = make(map[uintptr]slog.Level) h.siteCache.Clear()
} }
// Vmodule sets the glog verbosity pattern. // Vmodule sets the glog verbosity pattern.
@ -133,10 +131,9 @@ func (h *GlogHandler) Vmodule(ruleset string) error {
} }
// Swap out the vmodule pattern for the new filter system // Swap out the vmodule pattern for the new filter system
h.lock.Lock() h.lock.Lock()
defer h.lock.Unlock()
h.patterns = filter h.patterns = filter
h.siteCache = make(map[uintptr]slog.Level) h.lock.Unlock()
h.siteCache.Clear()
h.override.Store(len(filter) != 0) h.override.Store(len(filter) != 0)
return nil return nil
@ -152,18 +149,15 @@ func (h *GlogHandler) Enabled(ctx context.Context, lvl slog.Level) bool {
// WithAttrs implements slog.Handler, returning a new Handler whose attributes // WithAttrs implements slog.Handler, returning a new Handler whose attributes
// consist of both the receiver's attributes and the arguments. // consist of both the receiver's attributes and the arguments.
func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler { func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
patterns := []pattern{}
h.lock.RLock() h.lock.RLock()
siteCache := maps.Clone(h.siteCache) patterns = append(patterns, h.patterns...)
h.lock.RUnlock() h.lock.RUnlock()
patterns := []pattern{}
patterns = append(patterns, h.patterns...)
res := GlogHandler{ res := GlogHandler{
origin: h.origin.WithAttrs(attrs), origin: h.origin.WithAttrs(attrs),
patterns: patterns, patterns: patterns,
siteCache: siteCache, location: h.location,
location: h.location,
} }
res.level.Store(h.level.Load()) res.level.Store(h.level.Load())
@ -183,30 +177,28 @@ func (h *GlogHandler) WithGroup(name string) slog.Handler {
// local and backtrace filters, finally emitting it if either allow it through. // local and backtrace filters, finally emitting it if either allow it through.
func (h *GlogHandler) Handle(_ context.Context, r slog.Record) error { func (h *GlogHandler) Handle(_ context.Context, r slog.Record) error {
// Check callsite cache for previously calculated log levels // Check callsite cache for previously calculated log levels
h.lock.RLock() lvl, ok := h.siteCache.Load(r.PC)
lvl, ok := h.siteCache[r.PC]
h.lock.RUnlock()
// If we didn't cache the callsite yet, calculate it // If we didn't cache the callsite yet, calculate it
if !ok { if !ok {
h.lock.Lock()
fs := runtime.CallersFrames([]uintptr{r.PC}) fs := runtime.CallersFrames([]uintptr{r.PC})
frame, _ := fs.Next() frame, _ := fs.Next()
h.lock.RLock()
for _, rule := range h.patterns { for _, rule := range h.patterns {
if rule.pattern.MatchString(fmt.Sprintf("+%s", frame.File)) { if rule.pattern.MatchString(fmt.Sprintf("+%s", frame.File)) {
h.siteCache[r.PC], lvl, ok = rule.level, rule.level, true h.siteCache.Store(r.PC, rule.level)
lvl, ok = rule.level, true
} }
} }
h.lock.RUnlock()
// If no rule matched, use the default log lvl // If no rule matched, use the default log lvl
if !ok { if !ok {
lvl = slog.Level(h.level.Load()) lvl = slog.Level(h.level.Load())
h.siteCache[r.PC] = lvl h.siteCache.Store(r.PC, lvl)
} }
h.lock.Unlock()
} }
if lvl <= r.Level { if lvl.(slog.Level) <= r.Level {
return h.origin.Handle(context.Background(), r) return h.origin.Handle(context.Background(), r)
} }
return nil return nil