Source file
src/log/log.go
Documentation: log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package log
16
17 import (
18 "fmt"
19 "io"
20 "log/internal"
21 "os"
22 "runtime"
23 "sync"
24 "sync/atomic"
25 "time"
26 )
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 const (
43 Ldate = 1 << iota
44 Ltime
45 Lmicroseconds
46 Llongfile
47 Lshortfile
48 LUTC
49 Lmsgprefix
50 LstdFlags = Ldate | Ltime
51 )
52
53
54
55
56
57 type Logger struct {
58 outMu sync.Mutex
59 out io.Writer
60
61 prefix atomic.Pointer[string]
62 flag atomic.Int32
63 isDiscard atomic.Bool
64 }
65
66
67
68
69
70
71 func New(out io.Writer, prefix string, flag int) *Logger {
72 l := new(Logger)
73 l.SetOutput(out)
74 l.SetPrefix(prefix)
75 l.SetFlags(flag)
76 return l
77 }
78
79
80 func (l *Logger) SetOutput(w io.Writer) {
81 l.outMu.Lock()
82 defer l.outMu.Unlock()
83 l.out = w
84 l.isDiscard.Store(w == io.Discard)
85 }
86
87 var std = New(os.Stderr, "", LstdFlags)
88
89
90 func Default() *Logger { return std }
91
92
93 func itoa(buf *[]byte, i int, wid int) {
94
95 var b [20]byte
96 bp := len(b) - 1
97 for i >= 10 || wid > 1 {
98 wid--
99 q := i / 10
100 b[bp] = byte('0' + i - q*10)
101 bp--
102 i = q
103 }
104
105 b[bp] = byte('0' + i)
106 *buf = append(*buf, b[bp:]...)
107 }
108
109
110
111
112
113
114 func formatHeader(buf *[]byte, t time.Time, prefix string, flag int, file string, line int) {
115 if flag&Lmsgprefix == 0 {
116 *buf = append(*buf, prefix...)
117 }
118 if flag&(Ldate|Ltime|Lmicroseconds) != 0 {
119 if flag&LUTC != 0 {
120 t = t.UTC()
121 }
122 if flag&Ldate != 0 {
123 year, month, day := t.Date()
124 itoa(buf, year, 4)
125 *buf = append(*buf, '/')
126 itoa(buf, int(month), 2)
127 *buf = append(*buf, '/')
128 itoa(buf, day, 2)
129 *buf = append(*buf, ' ')
130 }
131 if flag&(Ltime|Lmicroseconds) != 0 {
132 hour, min, sec := t.Clock()
133 itoa(buf, hour, 2)
134 *buf = append(*buf, ':')
135 itoa(buf, min, 2)
136 *buf = append(*buf, ':')
137 itoa(buf, sec, 2)
138 if flag&Lmicroseconds != 0 {
139 *buf = append(*buf, '.')
140 itoa(buf, t.Nanosecond()/1e3, 6)
141 }
142 *buf = append(*buf, ' ')
143 }
144 }
145 if flag&(Lshortfile|Llongfile) != 0 {
146 if flag&Lshortfile != 0 {
147 short := file
148 for i := len(file) - 1; i > 0; i-- {
149 if file[i] == '/' {
150 short = file[i+1:]
151 break
152 }
153 }
154 file = short
155 }
156 *buf = append(*buf, file...)
157 *buf = append(*buf, ':')
158 itoa(buf, line, -1)
159 *buf = append(*buf, ": "...)
160 }
161 if flag&Lmsgprefix != 0 {
162 *buf = append(*buf, prefix...)
163 }
164 }
165
166 var bufferPool = sync.Pool{New: func() any { return new([]byte) }}
167
168 func getBuffer() *[]byte {
169 p := bufferPool.Get().(*[]byte)
170 *p = (*p)[:0]
171 return p
172 }
173
174 func putBuffer(p *[]byte) {
175
176
177
178
179
180
181 if cap(*p) > 64<<10 {
182 *p = nil
183 }
184 bufferPool.Put(p)
185 }
186
187
188
189
190
191
192
193 func (l *Logger) Output(calldepth int, s string) error {
194 calldepth++
195 return l.output(0, calldepth, func(b []byte) []byte {
196 return append(b, s...)
197 })
198 }
199
200
201
202 func (l *Logger) output(pc uintptr, calldepth int, appendOutput func([]byte) []byte) error {
203 if l.isDiscard.Load() {
204 return nil
205 }
206
207 now := time.Now()
208
209
210
211 prefix := l.Prefix()
212 flag := l.Flags()
213
214 var file string
215 var line int
216 if flag&(Lshortfile|Llongfile) != 0 {
217 if pc == 0 {
218 var ok bool
219 _, file, line, ok = runtime.Caller(calldepth)
220 if !ok {
221 file = "???"
222 line = 0
223 }
224 } else {
225 fs := runtime.CallersFrames([]uintptr{pc})
226 f, _ := fs.Next()
227 file = f.File
228 if file == "" {
229 file = "???"
230 }
231 line = f.Line
232 }
233 }
234
235 buf := getBuffer()
236 defer putBuffer(buf)
237 formatHeader(buf, now, prefix, flag, file, line)
238 *buf = appendOutput(*buf)
239 if len(*buf) == 0 || (*buf)[len(*buf)-1] != '\n' {
240 *buf = append(*buf, '\n')
241 }
242
243 l.outMu.Lock()
244 defer l.outMu.Unlock()
245 _, err := l.out.Write(*buf)
246 return err
247 }
248
249 func init() {
250 internal.DefaultOutput = func(pc uintptr, data []byte) error {
251 return std.output(pc, 0, func(buf []byte) []byte {
252 return append(buf, data...)
253 })
254 }
255 }
256
257
258
259 func (l *Logger) Print(v ...any) {
260 l.output(0, 2, func(b []byte) []byte {
261 return fmt.Append(b, v...)
262 })
263 }
264
265
266
267 func (l *Logger) Printf(format string, v ...any) {
268 l.output(0, 2, func(b []byte) []byte {
269 return fmt.Appendf(b, format, v...)
270 })
271 }
272
273
274
275 func (l *Logger) Println(v ...any) {
276 l.output(0, 2, func(b []byte) []byte {
277 return fmt.Appendln(b, v...)
278 })
279 }
280
281
282 func (l *Logger) Fatal(v ...any) {
283 l.Output(2, fmt.Sprint(v...))
284 os.Exit(1)
285 }
286
287
288 func (l *Logger) Fatalf(format string, v ...any) {
289 l.Output(2, fmt.Sprintf(format, v...))
290 os.Exit(1)
291 }
292
293
294 func (l *Logger) Fatalln(v ...any) {
295 l.Output(2, fmt.Sprintln(v...))
296 os.Exit(1)
297 }
298
299
300 func (l *Logger) Panic(v ...any) {
301 s := fmt.Sprint(v...)
302 l.Output(2, s)
303 panic(s)
304 }
305
306
307 func (l *Logger) Panicf(format string, v ...any) {
308 s := fmt.Sprintf(format, v...)
309 l.Output(2, s)
310 panic(s)
311 }
312
313
314 func (l *Logger) Panicln(v ...any) {
315 s := fmt.Sprintln(v...)
316 l.Output(2, s)
317 panic(s)
318 }
319
320
321
322 func (l *Logger) Flags() int {
323 return int(l.flag.Load())
324 }
325
326
327
328 func (l *Logger) SetFlags(flag int) {
329 l.flag.Store(int32(flag))
330 }
331
332
333 func (l *Logger) Prefix() string {
334 if p := l.prefix.Load(); p != nil {
335 return *p
336 }
337 return ""
338 }
339
340
341 func (l *Logger) SetPrefix(prefix string) {
342 l.prefix.Store(&prefix)
343 }
344
345
346 func (l *Logger) Writer() io.Writer {
347 l.outMu.Lock()
348 defer l.outMu.Unlock()
349 return l.out
350 }
351
352
353 func SetOutput(w io.Writer) {
354 std.SetOutput(w)
355 }
356
357
358
359 func Flags() int {
360 return std.Flags()
361 }
362
363
364
365 func SetFlags(flag int) {
366 std.SetFlags(flag)
367 }
368
369
370 func Prefix() string {
371 return std.Prefix()
372 }
373
374
375 func SetPrefix(prefix string) {
376 std.SetPrefix(prefix)
377 }
378
379
380 func Writer() io.Writer {
381 return std.Writer()
382 }
383
384
385
386
387
388 func Print(v ...any) {
389 std.output(0, 2, func(b []byte) []byte {
390 return fmt.Append(b, v...)
391 })
392 }
393
394
395
396 func Printf(format string, v ...any) {
397 std.output(0, 2, func(b []byte) []byte {
398 return fmt.Appendf(b, format, v...)
399 })
400 }
401
402
403
404 func Println(v ...any) {
405 std.output(0, 2, func(b []byte) []byte {
406 return fmt.Appendln(b, v...)
407 })
408 }
409
410
411 func Fatal(v ...any) {
412 std.Output(2, fmt.Sprint(v...))
413 os.Exit(1)
414 }
415
416
417 func Fatalf(format string, v ...any) {
418 std.Output(2, fmt.Sprintf(format, v...))
419 os.Exit(1)
420 }
421
422
423 func Fatalln(v ...any) {
424 std.Output(2, fmt.Sprintln(v...))
425 os.Exit(1)
426 }
427
428
429 func Panic(v ...any) {
430 s := fmt.Sprint(v...)
431 std.Output(2, s)
432 panic(s)
433 }
434
435
436 func Panicf(format string, v ...any) {
437 s := fmt.Sprintf(format, v...)
438 std.Output(2, s)
439 panic(s)
440 }
441
442
443 func Panicln(v ...any) {
444 s := fmt.Sprintln(v...)
445 std.Output(2, s)
446 panic(s)
447 }
448
449
450
451
452
453
454
455
456 func Output(calldepth int, s string) error {
457 return std.Output(calldepth+1, s)
458 }
459
View as plain text