| 1 | package logger |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "log/slog" |
| 6 | "sync" |
| 7 | "testing" |
| 8 | ) |
| 9 | |
| 10 | type capturedRecord struct { |
| 11 | level slog.Level |
| 12 | msg string |
| 13 | } |
| 14 | |
| 15 | type captureHandler struct { |
| 16 | mu sync.Mutex |
| 17 | minLvl slog.Level |
| 18 | records []capturedRecord |
| 19 | } |
| 20 | |
| 21 | func newCaptureHandler(minLvl slog.Level) *captureHandler { |
| 22 | return &captureHandler{minLvl: minLvl} |
| 23 | } |
| 24 | |
| 25 | func (h *captureHandler) Enabled(_ context.Context, lvl slog.Level) bool { |
| 26 | return lvl >= h.minLvl |
| 27 | } |
| 28 | |
| 29 | func (h *captureHandler) Handle(_ context.Context, r slog.Record) error { |
| 30 | h.mu.Lock() |
| 31 | defer h.mu.Unlock() |
| 32 | h.records = append(h.records, capturedRecord{ |
| 33 | level: r.Level, |
| 34 | msg: r.Message, |
| 35 | }) |
| 36 | return nil |
| 37 | } |
| 38 | |
| 39 | func (h *captureHandler) WithAttrs(_ []slog.Attr) slog.Handler { |
| 40 | return h |
| 41 | } |
| 42 | |
| 43 | func (h *captureHandler) WithGroup(_ string) slog.Handler { |
| 44 | return h |
| 45 | } |
| 46 | |
| 47 | func (h *captureHandler) count() int { |
| 48 | h.mu.Lock() |
| 49 | defer h.mu.Unlock() |
| 50 | return len(h.records) |
| 51 | } |
| 52 | |
| 53 | func (h *captureHandler) last() capturedRecord { |
| 54 | h.mu.Lock() |
| 55 | defer h.mu.Unlock() |
| 56 | if len(h.records) == 0 { |
| 57 | return capturedRecord{} |
| 58 | } |
| 59 | return h.records[len(h.records)-1] |
| 60 | } |
| 61 | |
| 62 | func setTestLevel(t *testing.T, level slog.Level) { |
| 63 | t.Helper() |
| 64 | prev := Level.lvl.Level() |
| 65 | Level.Set(level) |
| 66 | t.Cleanup(func() { |
| 67 | Level.Set(prev) |
| 68 | }) |
| 69 | } |
| 70 | |
| 71 | func newTestLogger(level slog.Level) (*Logger, *captureHandler) { |
| 72 | handler := newCaptureHandler(level) |
| 73 | return &Logger{sl: slog.New(handler), rl: newRateLimiter()}, handler |
| 74 | } |