4
4
//
5
5
// The examples are the best way to understand how to use this library effectively.
6
6
//
7
- // This package provides a high level API around the Sink interface.
8
- // The implementations are in the sloggers subdirectory.
7
+ // The Logger type implements a high level API around the Sink interface.
8
+ // Logger implements Sink as well to allow composition.
9
+ //
10
+ // Implementations of the Sink interface are available in the sloggers subdirectory.
9
11
package slog // import "cdr.dev/slog"
10
12
11
13
import (
@@ -37,7 +39,7 @@ func (l Logger) LogEntry(ctx context.Context, e SinkEntry) {
37
39
}
38
40
39
41
e .Fields = l .fields .append (e .Fields )
40
- e .Names = appendName ( e . Names , l . names ... )
42
+ e .LoggerNames = appendNames ( l . names , e . LoggerNames ... )
41
43
42
44
for _ , s := range l .sinks {
43
45
s .LogEntry (ctx , e )
@@ -51,16 +53,17 @@ func (l Logger) Sync() {
51
53
}
52
54
}
53
55
54
- // Logger wraps Sink with a easy to use API .
56
+ // Logger wraps Sink with a nice API to log entries .
55
57
//
56
58
// Logger is safe for concurrent use.
57
59
type Logger struct {
60
+ sinks []Sink
61
+ level Level
62
+
58
63
names []string
59
- sinks []Sink
60
- skip int
61
64
fields Map
62
- level Level
63
65
66
+ skip int
64
67
exit func (int )
65
68
}
66
69
@@ -91,54 +94,42 @@ func (l Logger) Warn(ctx context.Context, msg string, fields ...Field) {
91
94
92
95
// Error logs the msg and fields at LevelError.
93
96
//
94
- // It will also Sync() before returning .
97
+ // It will then Sync().
95
98
func (l Logger ) Error (ctx context.Context , msg string , fields ... Field ) {
96
99
l .log (ctx , LevelError , msg , fields )
97
100
l .Sync ()
98
101
}
99
102
100
103
// Critical logs the msg and fields at LevelCritical.
101
104
//
102
- // It will also Sync() before returning .
105
+ // It will then Sync().
103
106
func (l Logger ) Critical (ctx context.Context , msg string , fields ... Field ) {
104
107
l .log (ctx , LevelCritical , msg , fields )
105
108
l .Sync ()
106
109
}
107
110
108
111
// Fatal logs the msg and fields at LevelFatal.
109
112
//
110
- // It will also Sync() before returning .
113
+ // It will then Sync() and os.Exit(1) .
111
114
func (l Logger ) Fatal (ctx context.Context , msg string , fields ... Field ) {
112
115
l .log (ctx , LevelFatal , msg , fields )
113
116
l .Sync ()
114
117
l .exit (1 )
115
118
}
116
119
117
- var helpers sync.Map
118
-
119
- // Helper marks the calling function as a helper
120
- // and skips it for source location information.
121
- // It's the slog equivalent of testing.TB.Helper().
122
- func Helper () {
123
- _ , _ , fn := location (1 )
124
- helpers .LoadOrStore (fn , struct {}{})
125
- }
126
-
127
120
// With returns a Logger that prepends the given fields on every
128
121
// logged entry.
122
+ //
129
123
// It will append to any fields already in the Logger.
130
124
func (l Logger ) With (fields ... Field ) Logger {
131
125
l .fields = l .fields .append (fields )
132
126
return l
133
127
}
134
128
135
- // Named names the logger.
136
- // If there is already a name set, it will be joined by ".".
137
- // E.g. if the name is currently "my_component" and then later
138
- // the name "my_pkg" is set, then the final component will be
139
- // "my_component.my_pkg".
129
+ // Named appends the name to the set names
130
+ // on the logger.
140
131
func (l Logger ) Named (name string ) Logger {
141
- l .names = appendName (l .names , name )
132
+ l .names = appendNames (l .names , name )
142
133
return l
143
134
}
144
135
@@ -149,6 +140,33 @@ func (l Logger) Leveled(level Level) Logger {
149
140
return l
150
141
}
151
142
143
+ func (l Logger ) log (ctx context.Context , level Level , msg string , fields Map ) {
144
+ ent := l .entry (ctx , level , msg , fields )
145
+ l .LogEntry (ctx , ent )
146
+ }
147
+
148
+ func (l Logger ) entry (ctx context.Context , level Level , msg string , fields Map ) SinkEntry {
149
+ ent := SinkEntry {
150
+ Time : time .Now ().UTC (),
151
+ Level : level ,
152
+ Message : msg ,
153
+ Fields : fieldsFromContext (ctx ).append (fields ),
154
+ SpanContext : trace .FromContext (ctx ).SpanContext (),
155
+ }
156
+ ent = ent .fillLoc (l .skip + 3 )
157
+ return ent
158
+ }
159
+
160
+ var helpers sync.Map
161
+
162
+ // Helper marks the calling function as a helper
163
+ // and skips it for source location information.
164
+ // It's the slog equivalent of testing.TB.Helper().
165
+ func Helper () {
166
+ _ , _ , fn := location (1 )
167
+ helpers .LoadOrStore (fn , struct {}{})
168
+ }
169
+
152
170
func (ent SinkEntry ) fillFromFrame (f runtime.Frame ) SinkEntry {
153
171
ent .Func = f .Function
154
172
ent .File = f .File
@@ -182,27 +200,14 @@ func location(skip int) (file string, line int, fn string) {
182
200
return file , line , f .Name ()
183
201
}
184
202
185
- func appendName (names []string , names2 ... string ) []string {
186
- names = append ([]string (nil ), names ... )
187
- names = append (names , names2 ... )
188
- return names
189
- }
190
-
191
- func (l Logger ) log (ctx context.Context , level Level , msg string , fields Map ) {
192
- ent := l .entry (ctx , level , msg , fields )
193
- l .LogEntry (ctx , ent )
194
- }
195
-
196
- func (l Logger ) entry (ctx context.Context , level Level , msg string , fields Map ) SinkEntry {
197
- ent := SinkEntry {
198
- Time : time .Now ().UTC (),
199
- Level : level ,
200
- Message : msg ,
201
- Fields : fieldsFromContext (ctx ).append (fields ),
202
- SpanContext : trace .FromContext (ctx ).SpanContext (),
203
+ func appendNames (names []string , names2 ... string ) []string {
204
+ if len (names2 ) == 0 {
205
+ return names
203
206
}
204
- ent = ent .fillLoc (l .skip + 3 )
205
- return ent
207
+ names3 := make ([]string , 0 , len (names )+ len (names2 ))
208
+ names3 = append (names3 , names ... )
209
+ names3 = append (names3 , names2 ... )
210
+ return names3
206
211
}
207
212
208
213
// Field represents a log field.
@@ -222,6 +227,7 @@ func M(fs ...Field) Map {
222
227
}
223
228
224
229
// Value represents a log value.
230
+ //
225
231
// Implement SlogValue in your own types to override
226
232
// the value encoded when logging.
227
233
type Value interface {
@@ -245,8 +251,9 @@ func fieldsFromContext(ctx context.Context) Map {
245
251
}
246
252
247
253
// With returns a context that contains the given fields.
248
- // Any logs written with the provided context will have
249
- // the given logs prepended.
254
+ //
255
+ // Any logs written with the provided context will have the given logs prepended.
256
+ //
250
257
// It will append to any fields already in ctx.
251
258
func With (ctx context.Context , fields ... Field ) context.Context {
252
259
f1 := fieldsFromContext (ctx )
@@ -262,9 +269,7 @@ type SinkEntry struct {
262
269
Level Level
263
270
Message string
264
271
265
- // Names represents the chain of names on the
266
- // logger constructed with Named.
267
- Names []string
272
+ LoggerNames []string
268
273
269
274
Func string
270
275
File string
@@ -279,6 +284,8 @@ type SinkEntry struct {
279
284
type Level int
280
285
281
286
// The supported log levels.
287
+ //
288
+ // The default level is Info.
282
289
const (
283
290
LevelDebug Level = iota
284
291
LevelInfo
@@ -297,17 +304,11 @@ var levelStrings = map[Level]string{
297
304
LevelFatal : "FATAL" ,
298
305
}
299
306
307
+ // String implements fmt.Stringer.
300
308
func (l Level ) String () string {
301
309
s , ok := levelStrings [l ]
302
310
if ! ok {
303
311
return fmt .Sprintf ("slog.Level(%v)" , int (l ))
304
312
}
305
313
return s
306
314
}
307
-
308
- func (f1 Map ) append (f2 Map ) Map {
309
- f3 := make (Map , 0 , len (f1 )+ len (f2 ))
310
- f3 = append (f3 , f1 ... )
311
- f3 = append (f3 , f2 ... )
312
- return f3
313
- }
0 commit comments