blob: d113bf0e7e505741cca0e6a8adf3f461dbd8644b [file] [log] [blame]
Earl Lee2e463fb2025-04-17 11:22:22 -07001// Package skribe defines sketch-wide logging types and functions.
2//
3// Logging happens via slog.
4package skribe
5
6import (
7 "context"
8 "io"
9 "log/slog"
10 "slices"
11 "strings"
12)
13
14type attrsKey struct{}
15
16func Redact(arr []string) []string {
17 ret := []string{}
18 for _, s := range arr {
19 if strings.HasPrefix(s, "ANTHROPIC_API_KEY=") {
20 ret = append(ret, "ANTHROPIC_API_KEY=[REDACTED]")
21 } else {
22 ret = append(ret, s)
23 }
24 }
25 return ret
26}
27
28func ContextWithAttr(ctx context.Context, add ...slog.Attr) context.Context {
29 attrs := slices.Clone(Attrs(ctx))
30 attrs = append(attrs, add...)
31 return context.WithValue(ctx, attrsKey{}, attrs)
32}
33
34func Attrs(ctx context.Context) []slog.Attr {
35 attrs, _ := ctx.Value(attrsKey{}).([]slog.Attr)
36 return attrs
37}
38
39func AttrsWrap(h slog.Handler) slog.Handler {
40 return &augmentHandler{Handler: h}
41}
42
43type augmentHandler struct {
44 slog.Handler
45}
46
47func (h *augmentHandler) Handle(ctx context.Context, r slog.Record) error {
48 attrs := Attrs(ctx)
49 r.AddAttrs(attrs...)
50 return h.Handler.Handle(ctx, r)
51}
52
53type multiHandler struct {
54 AllHandler slog.Handler
55}
56
57// Enabled implements slog.Handler. Ignores slog.Level - if there's a logger, this returns true.
58func (mh *multiHandler) Enabled(ctx context.Context, l slog.Level) bool {
59 _, ok := ctx.Value(skribeCtxHandlerKey).(slog.Handler)
60 return ok
61}
62
63// WithAttrs implements slog.Handler.
64func (mh *multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
65 panic("unimplemented")
66}
67
68// WithGroup implements slog.Handler.
69func (mh *multiHandler) WithGroup(name string) slog.Handler {
70 panic("unimplemented")
71}
72
73func NewMultiHandler() *multiHandler {
74 return &multiHandler{}
75}
76
77type scribeCtxKeyType string
78
79const skribeCtxHandlerKey scribeCtxKeyType = "skribe-handlerKey"
80
81func (mh *multiHandler) NewSlogHandlerCtx(ctx context.Context, logFile io.Writer) context.Context {
82 h := slog.NewJSONHandler(logFile, &slog.HandlerOptions{Level: slog.LevelDebug})
83 w := AttrsWrap(h)
84 return context.WithValue(ctx, skribeCtxHandlerKey, w)
85}
86
87func (mh *multiHandler) Handle(ctx context.Context, r slog.Record) error {
88 if mh.AllHandler != nil {
89 if err := mh.AllHandler.Handle(ctx, r); err != nil {
90 return err
91 }
92 }
93 attrs := Attrs(ctx)
94 r.AddAttrs(attrs...)
95 handler, ok := ctx.Value(skribeCtxHandlerKey).(slog.Handler)
96 if !ok {
97 panic("no skribeCtxHandlerKey value in ctx")
98 }
99 return handler.Handle(ctx, r)
100}