-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuilder.go
More file actions
192 lines (177 loc) · 5.68 KB
/
Copy pathbuilder.go
File metadata and controls
192 lines (177 loc) · 5.68 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package loglayer
import "context"
// LogBuilder accumulates per-log metadata, error, and context.Context before
// dispatching to a log level method. Obtain one via LogLayer.WithMetadata,
// LogLayer.WithError, or LogLayer.WithContext.
//
// LogBuilders are intended to be single-use and stack-allocated. Build, chain,
// and terminate inline:
//
// log.WithContext(ctx).WithMetadata(meta).WithError(err).Error("failed")
//
// Holding a *LogBuilder past its terminal call works but discards the
// stack-allocation benefit.
type LogBuilder struct {
layer *LogLayer
plugins *pluginSet
metadata any
err error
ctx context.Context
groups []string
}
func newLogBuilder(l *LogLayer) *LogBuilder {
return &LogBuilder{layer: l, plugins: l.loadPlugins()}
}
// WithMetadata attaches metadata to the log entry. Accepts any value: a struct,
// a map, or any other type. Serialization is handled by the transport.
// Calling this multiple times replaces the previous value.
//
// OnMetadataCalled plugin hooks run here. A hook returning nil drops the
// metadata entirely for this entry.
func (b *LogBuilder) WithMetadata(v any) *LogBuilder {
b.metadata = b.plugins.runOnMetadataCalled(v)
return b
}
// WithError attaches an error to the log entry.
func (b *LogBuilder) WithError(err error) *LogBuilder {
b.err = err
return b
}
// WithContext attaches a context.Context to this single log entry, overriding
// any context bound to the parent logger via (*LogLayer).WithContext for this
// emission only.
//
// For the persistent variant (bind once, every subsequent emission carries
// the ctx), use (*LogLayer).WithContext instead.
//
// Passing nil clears any per-call ctx previously set on this builder.
// On a fresh builder it has no observable effect (the layer's bound ctx,
// if any, still applies on dispatch).
func (b *LogBuilder) WithContext(ctx context.Context) *LogBuilder {
b.ctx = ctx
return b
}
// WithGroup tags this single log entry with one or more group names.
// Routing rules in Config.Groups decide which transports receive the
// entry. Tags are merged with any persistent groups assigned via
// (*LogLayer).WithGroup.
//
// Calling this multiple times accumulates groups (deduplicated).
func (b *LogBuilder) WithGroup(groups ...string) *LogBuilder {
if len(groups) == 0 {
return b
}
merged := mergeGroups(b.groups, groups)
// Detach from the caller's variadic backing on the first WithGroup
// call so a mutation between WithGroup and the terminal level call
// can't leak through.
if len(b.groups) == 0 {
merged = append([]string(nil), merged...)
}
b.groups = merged
return b
}
// Trace dispatches the accumulated entry at the trace level.
func (b *LogBuilder) Trace(messages ...any) {
if !b.layer.levels.isEnabled(LogLevelTrace) {
return
}
var src *Source
if b.layer.config.Source.Enabled {
src = captureSource(1)
}
b.dispatch(LogLevelTrace, messages, src)
}
// Info dispatches the accumulated entry at the info level.
func (b *LogBuilder) Info(messages ...any) {
if !b.layer.levels.isEnabled(LogLevelInfo) {
return
}
var src *Source
if b.layer.config.Source.Enabled {
src = captureSource(1)
}
b.dispatch(LogLevelInfo, messages, src)
}
// Warn dispatches the accumulated entry at the warn level.
func (b *LogBuilder) Warn(messages ...any) {
if !b.layer.levels.isEnabled(LogLevelWarn) {
return
}
var src *Source
if b.layer.config.Source.Enabled {
src = captureSource(1)
}
b.dispatch(LogLevelWarn, messages, src)
}
// Error dispatches the accumulated entry at the error level.
func (b *LogBuilder) Error(messages ...any) {
if !b.layer.levels.isEnabled(LogLevelError) {
return
}
var src *Source
if b.layer.config.Source.Enabled {
src = captureSource(1)
}
b.dispatch(LogLevelError, messages, src)
}
// Debug dispatches the accumulated entry at the debug level.
func (b *LogBuilder) Debug(messages ...any) {
if !b.layer.levels.isEnabled(LogLevelDebug) {
return
}
var src *Source
if b.layer.config.Source.Enabled {
src = captureSource(1)
}
b.dispatch(LogLevelDebug, messages, src)
}
// Fatal dispatches the accumulated entry at the fatal level.
// Calls os.Exit(1) after dispatch unless Config.DisableFatalExit is set.
func (b *LogBuilder) Fatal(messages ...any) {
if !b.layer.levels.isEnabled(LogLevelFatal) {
return
}
var src *Source
if b.layer.config.Source.Enabled {
src = captureSource(1)
}
b.dispatch(LogLevelFatal, messages, src)
}
// Panic dispatches the accumulated entry at the panic level then panics
// with the joined message string. The panic is recoverable; see
// LogLayer.Panic for the contract.
func (b *LogBuilder) Panic(messages ...any) {
if !b.layer.levels.isEnabled(LogLevelPanic) {
return
}
var src *Source
if b.layer.config.Source.Enabled {
src = captureSource(1)
}
b.dispatch(LogLevelPanic, messages, src)
}
func (b *LogBuilder) dispatch(level LogLevel, messages []any, source *Source) {
// Prefix flows through TransportParams.Prefix; each transport
// renders it however it wants (most call the
// transport.JoinPrefixAndMessages helper to fold it into the
// first message string).
//
// Hot path: builder has no per-call groups, so pass the layer's
// assigned groups straight through. mergeGroups is out-of-line and
// would be a measurable hit per emission for the dominant case.
groups := b.layer.assignedGroups
if len(b.groups) > 0 {
groups = mergeGroups(groups, b.groups)
}
// Per-call WithContext on the builder overrides the layer's bound ctx.
ctx := b.ctx
if ctx == nil {
ctx = b.layer.boundCtx
}
fields := b.layer.fields
if !b.layer.muteFields.Load() && b.layer.hasLazyFields.Load() {
fields = resolveLazyFields(fields)
}
b.layer.processLog(level, messages, fields, ctx, b.metadata, b.err, source, groups, b.plugins)
}