diff options
author | Benjamin Chausse <benjamin@chausse.xyz> | 2025-02-03 01:12:45 -0500 |
---|---|---|
committer | Benjamin Chausse <benjamin@chausse.xyz> | 2025-02-03 01:12:45 -0500 |
commit | 5389e1a5d26fdbf2441fa5a1e101999e8449b9d1 (patch) | |
tree | 069cd37cb8e556c1ba3b47c3ea8576a1aa91ea2c /internal/logging/trace.go |
Batman
Diffstat (limited to 'internal/logging/trace.go')
-rw-r--r-- | internal/logging/trace.go | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/internal/logging/trace.go b/internal/logging/trace.go new file mode 100644 index 0000000..8900727 --- /dev/null +++ b/internal/logging/trace.go @@ -0,0 +1,61 @@ +package logging + +import ( + "context" + "log/slog" + "runtime" + "strconv" + "strings" +) + +const ( + prgCount = 20 + defSkip = 6 +) + +type stackTracer struct { + h slog.Handler + nSkip int +} + +func (h stackTracer) Enabled(ctx context.Context, lvl slog.Level) bool { + return h.h.Enabled(ctx, lvl) +} + +func (h stackTracer) WithAttrs(attrs []slog.Attr) slog.Handler { + return h.h.WithAttrs(attrs) +} + +func (h stackTracer) WithGroup(name string) slog.Handler { + return h.h.WithGroup(name) +} + +func (h stackTracer) Handle(ctx context.Context, r slog.Record) error { + if r.Level < slog.LevelError { + return h.h.Handle(ctx, r) + } + + trace := h.GetTrace() + r.AddAttrs(slog.String("trace", trace)) + + return h.h.Handle(ctx, r) +} + +func (h stackTracer) GetTrace() string { + var b strings.Builder + pc := make([]uintptr, prgCount) + n := runtime.Callers(h.nSkip, pc) + frames := runtime.CallersFrames(pc[:n]) + + for frame, more := frames.Next(); more; frame, more = frames.Next() { + b.WriteString(frame.Function + "\n " + frame.File + ":" + strconv.Itoa(frame.Line) + "\n") + } + return b.String() +} + +func withStackTrace(h slog.Handler) slog.Handler { + return stackTracer{ + h: h, + nSkip: defSkip, + } +} |