-
Notifications
You must be signed in to change notification settings - Fork 5
/
handler.go
137 lines (121 loc) · 3 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
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package console
import (
"context"
"io"
"log/slog"
"os"
"strings"
"sync"
"time"
)
var bufferPool = &sync.Pool{
New: func() any { return new(buffer) },
}
var cwd, _ = os.Getwd()
// HandlerOptions are options for a ConsoleHandler.
// A zero HandlerOptions consists entirely of default values.
type HandlerOptions struct {
// 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
// Disable colorized output
NoColor bool
// TimeFormat is the format used for time.DateTime
TimeFormat string
// Theme defines the colorized output using ANSI escape sequences
Theme Theme
}
type Handler struct {
opts HandlerOptions
out io.Writer
group string
context buffer
enc *encoder
}
var _ slog.Handler = (*Handler)(nil)
// NewHandler creates a Handler that writes to w,
// using the given options.
// If opts is nil, the default options are used.
func NewHandler(out io.Writer, opts *HandlerOptions) *Handler {
if opts == nil {
opts = new(HandlerOptions)
}
if opts.Level == nil {
opts.Level = slog.LevelInfo
}
if opts.TimeFormat == "" {
opts.TimeFormat = time.DateTime
}
if opts.Theme == nil {
opts.Theme = NewDefaultTheme()
}
return &Handler{
opts: *opts, // Copy struct
out: out,
group: "",
context: nil,
enc: &encoder{opts: *opts},
}
}
// Enabled implements slog.Handler.
func (h *Handler) Enabled(_ context.Context, l slog.Level) bool {
return l >= h.opts.Level.Level()
}
// Handle implements slog.Handler.
func (h *Handler) Handle(_ context.Context, rec slog.Record) error {
buf := bufferPool.Get().(*buffer)
h.enc.writeTimestamp(buf, rec.Time)
h.enc.writeLevel(buf, rec.Level)
if h.opts.AddSource && rec.PC > 0 {
h.enc.writeSource(buf, rec.PC, cwd)
}
h.enc.writeMessage(buf, rec.Level, rec.Message)
buf.copy(&h.context)
rec.Attrs(func(a slog.Attr) bool {
h.enc.writeAttr(buf, a, h.group)
return true
})
h.enc.NewLine(buf)
if _, err := buf.WriteTo(h.out); err != nil {
buf.Reset()
bufferPool.Put(buf)
return err
}
bufferPool.Put(buf)
return nil
}
// WithAttrs implements slog.Handler.
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
newCtx := h.context
for _, a := range attrs {
h.enc.writeAttr(&newCtx, a, h.group)
}
newCtx.Clip()
return &Handler{
opts: h.opts,
out: h.out,
group: h.group,
context: newCtx,
enc: h.enc,
}
}
// WithGroup implements slog.Handler.
func (h *Handler) WithGroup(name string) slog.Handler {
name = strings.TrimSpace(name)
if h.group != "" {
name = h.group + "." + name
}
return &Handler{
opts: h.opts,
out: h.out,
group: name,
context: h.context,
enc: h.enc,
}
}