-
Notifications
You must be signed in to change notification settings - Fork 0
/
logger.go
121 lines (106 loc) · 3.14 KB
/
logger.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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package slim
import (
"io"
"log/slog"
"os"
)
type Logger struct {
*slog.Logger
output *outputVar
level *slog.LevelVar
}
type LoggerOptions struct {
Output io.Writer
// AddSource causes the handler to compute the source code position
// of the log statement and add a SourceKey attribute to the output.
AddSource bool
// Level reports the minimum record level that will be logged.
// The handler discards records with lower levels.
// If Level is nil, the handler assumes LevelInfo.
// The handler calls Level.Level for each record processed;
// to adjust the minimum level dynamically, use a LevelVar.
Level slog.Leveler
// ReplaceAttr is called to rewrite each non-group attribute before it is logged.
// The attribute's value has been resolved (see [Value.Resolve]).
// If ReplaceAttr returns a zero Attr, the attribute is discarded.
//
// The built-in attributes with keys "time", "level", "source", and "msg"
// are passed to this function, except that time is omitted
// if zero, and source is omitted if AddSource is false.
//
// The first argument is a list of currently open groups that contain the
// Attr. It must not be retained or modified. ReplaceAttr is never called
// for Group attributes, only their contents. For example, the attribute
// list
//
// Int("a", 1), Group("g", Int("b", 2)), Int("c", 3)
//
// results in consecutive calls to ReplaceAttr with the following arguments:
//
// nil, Int("a", 1)
// []string{"g"}, Int("b", 2)
// nil, Int("c", 3)
//
// ReplaceAttr can be used to change the default keys of the built-in
// attributes, convert types (for example, to replace a `time.Time` with the
// integer seconds since the Unix epoch), sanitize personal information, or
// remove attributes from the output.
ReplaceAttr func(groups []string, a slog.Attr) slog.Attr
NewHandler func(w io.Writer, opts *slog.HandlerOptions) slog.Handler
}
type outputVar struct {
io.Writer
}
func (o *outputVar) Write(p []byte) (int, error) {
return o.Writer.Write(p)
}
func NewLogger(opts *LoggerOptions) *Logger {
if opts.Output == nil {
opts.Output = os.Stderr
}
if opts.Level == nil {
opts.Level = slog.LevelError
}
if opts.NewHandler == nil {
opts.NewHandler = func(w io.Writer, opts *slog.HandlerOptions) slog.Handler {
return slog.NewTextHandler(w, opts)
}
}
level := &slog.LevelVar{}
output := &outputVar{opts.Output}
level.Set(opts.Level.Level())
return &Logger{
Logger: slog.New(opts.NewHandler(output, &slog.HandlerOptions{
AddSource: opts.AddSource,
Level: level,
ReplaceAttr: opts.ReplaceAttr,
})),
output: output,
level: level,
}
}
func (l *Logger) Output() io.Writer {
return l.output.Writer
}
func (l *Logger) SetLevel(level slog.Level) (oldLevel slog.Level) {
oldLevel = l.level.Level()
l.level.Set(level)
return
}
func (l *Logger) Level() slog.Leveler {
return l.level
}
func (l *Logger) With(args ...any) *Logger {
return &Logger{
Logger: l.Logger.With(args...),
output: l.output,
level: l.level,
}
}
func (l *Logger) WithGroup(name string) *Logger {
return &Logger{
Logger: l.Logger.WithGroup(name),
output: l.output,
level: l.level,
}
}