-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandler.go
85 lines (68 loc) · 2.1 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// Copyright (c) 2024 The sloth authors
// Use of this source code is governed by a MIT license found in the LICENSE file.
/*
Package rate provides a Handler that limits records within the given rate.
It caps the CPU and I/O load of logging while attempting to preserve a representative subset of your logs.
It logs the first N records with a given level and message each interval.
If more records with the same level and message are seen during the same interval,
every Mth message is logged and the rest are dropped.
Keep in mind that the implementation is optimized for speed over absolute precision;
under load, each interval may be slightly over- or under-sampled.
*/
package rate
import (
"context"
"log/slog"
"time"
)
// Handler limits records with give rate, which caps the CPU and I/O load
// of logging while attempting to preserve a representative subset of your logs.
//
// To create a new Handler, call [New].
type Handler struct {
handler slog.Handler
interval time.Duration
first uint64
every uint64
counts *counters
}
// New creates a new Handler with the given Option(s).
func New(handler slog.Handler, opts ...Option) Handler {
if handler == nil {
panic("cannot create Handler with nil handler")
}
option := &options{
handler: handler,
counts: &counters{},
every: 100, //nolint:mnd
}
for _, opt := range opts {
opt(option)
}
if option.interval <= 0 {
option.interval = time.Second
}
if option.first == 0 {
option.first = 100
}
return Handler(*option)
}
func (h Handler) Enabled(ctx context.Context, level slog.Level) bool {
return h.handler.Enabled(ctx, level)
}
func (h Handler) Handle(ctx context.Context, record slog.Record) error {
count := h.counts.get(record.Level, record.Message)
n := count.Inc(record.Time, h.interval)
if n > h.first && (h.every == 0 || (n-h.first)%h.every != 0) {
return nil
}
return h.handler.Handle(ctx, record)
}
func (h Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
h.handler = h.handler.WithAttrs(attrs)
return h
}
func (h Handler) WithGroup(name string) slog.Handler {
h.handler = h.handler.WithGroup(name)
return h
}