main
Raw Download raw file
  1// Copyright 2014-2022 Ulrich Kunitz. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5// Package xlog provides a simple logging package that allows to disable
  6// certain message categories. It defines a type, Logger, with multiple
  7// methods for formatting output. The package has also a predefined
  8// 'standard' Logger accessible through helper function Print[f|ln],
  9// Fatal[f|ln], Panic[f|ln], Warn[f|ln], Print[f|ln] and Debug[f|ln]
 10// that are easier to use then creating a Logger manually. That logger
 11// writes to standard error and prints the date and time of each logged
 12// message, which can be configured using the function SetFlags.
 13//
 14// The Fatal functions call os.Exit(1) after the message is output
 15// unless not suppressed by the flags. The Panic functions call panic
 16// after the writing the log message unless suppressed.
 17package xlog
 18
 19import (
 20	"fmt"
 21	"io"
 22	"os"
 23	"runtime"
 24	"sync"
 25	"time"
 26)
 27
 28// The flags define what information is prefixed to each log entry
 29// generated by the Logger. The Lno* versions allow the suppression of
 30// specific output. The bits are or'ed together to control what will be
 31// printed. There is no control over the order of the items printed and
 32// the format. The full format is:
 33//
 34//	2009-01-23 01:23:23.123123 /a/b/c/d.go:23: message
 35const (
 36	Ldate         = 1 << iota // the date: 2009-01-23
 37	Ltime                     // the time: 01:23:23
 38	Lmicroseconds             // microsecond resolution: 01:23:23.123123
 39	Llongfile                 // full file name and line number: /a/b/c/d.go:23
 40	Lshortfile                // final file name element and line number: d.go:23
 41	Lnopanic                  // suppresses output from Panic[f|ln] but not the panic call
 42	Lnofatal                  // suppresses output from Fatal[f|ln] but not the exit
 43	Lnowarn                   // suppresses output from Warn[f|ln]
 44	Lnoprint                  // suppresses output from Print[f|ln]
 45	Lnodebug                  // suppresses output from Debug[f|ln]
 46	// initial values for the standard logger
 47	Lstdflags = Ldate | Ltime | Lnodebug
 48)
 49
 50// A Logger represents an active logging object that generates lines of
 51// output to an io.Writer. Each logging operation if not suppressed
 52// makes a single call to the Writer's Write method. A Logger can be
 53// used simultaneously from multiple goroutines; it guarantees to
 54// serialize access to the Writer.
 55type Logger struct {
 56	mu sync.Mutex // ensures atomic writes; and protects the following
 57	// fields
 58	prefix string    // prefix to write at beginning of each line
 59	flag   int       // properties
 60	out    io.Writer // destination for output
 61	buf    []byte    // for accumulating text to write
 62}
 63
 64// New creates a new Logger. The out argument sets the destination to
 65// which the log output will be written. The prefix appears at the
 66// beginning of each log line. The flag argument defines the logging
 67// properties.
 68func New(out io.Writer, prefix string, flag int) *Logger {
 69	return &Logger{out: out, prefix: prefix, flag: flag}
 70}
 71
 72// std is the standard logger used by the package scope functions.
 73var std = New(os.Stderr, "", Lstdflags)
 74
 75// itoa converts the integer to ASCII. A negative widths will avoid
 76// zero-padding. The function supports only non-negative integers.
 77func itoa(buf *[]byte, i int, wid int) {
 78	var u = uint(i)
 79	if u == 0 && wid <= 1 {
 80		*buf = append(*buf, '0')
 81		return
 82	}
 83	var b [32]byte
 84	bp := len(b)
 85	for ; u > 0 || wid > 0; u /= 10 {
 86		bp--
 87		wid--
 88		b[bp] = byte(u%10) + '0'
 89	}
 90	*buf = append(*buf, b[bp:]...)
 91}
 92
 93// formatHeader puts the header into the buf field of the buffer.
 94func (l *Logger) formatHeader(t time.Time, file string, line int) {
 95	l.buf = append(l.buf, l.prefix...)
 96	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
 97		if l.flag&Ldate != 0 {
 98			year, month, day := t.Date()
 99			itoa(&l.buf, year, 4)
100			l.buf = append(l.buf, '-')
101			itoa(&l.buf, int(month), 2)
102			l.buf = append(l.buf, '-')
103			itoa(&l.buf, day, 2)
104			l.buf = append(l.buf, ' ')
105		}
106		if l.flag&(Ltime|Lmicroseconds) != 0 {
107			hour, min, sec := t.Clock()
108			itoa(&l.buf, hour, 2)
109			l.buf = append(l.buf, ':')
110			itoa(&l.buf, min, 2)
111			l.buf = append(l.buf, ':')
112			itoa(&l.buf, sec, 2)
113			if l.flag&Lmicroseconds != 0 {
114				l.buf = append(l.buf, '.')
115				itoa(&l.buf, t.Nanosecond()/1e3, 6)
116			}
117			l.buf = append(l.buf, ' ')
118		}
119	}
120	if l.flag&(Lshortfile|Llongfile) != 0 {
121		if l.flag&Lshortfile != 0 {
122			short := file
123			for i := len(file) - 1; i > 0; i-- {
124				if file[i] == '/' {
125					short = file[i+1:]
126					break
127				}
128			}
129			file = short
130		}
131		l.buf = append(l.buf, file...)
132		l.buf = append(l.buf, ':')
133		itoa(&l.buf, line, -1)
134		l.buf = append(l.buf, ": "...)
135	}
136}
137
138func (l *Logger) output(calldepth int, now time.Time, s string) error {
139	var file string
140	var line int
141	if l.flag&(Lshortfile|Llongfile) != 0 {
142		l.mu.Unlock()
143		var ok bool
144		_, file, line, ok = runtime.Caller(calldepth)
145		if !ok {
146			file = "???"
147			line = 0
148		}
149		l.mu.Lock()
150	}
151	l.buf = l.buf[:0]
152	l.formatHeader(now, file, line)
153	l.buf = append(l.buf, s...)
154	if len(s) == 0 || s[len(s)-1] != '\n' {
155		l.buf = append(l.buf, '\n')
156	}
157	_, err := l.out.Write(l.buf)
158	return err
159}
160
161// Output writes the string s with the header controlled by the flags to
162// the l.out writer. A newline will be appended if s doesn't end in a
163// newline. Calldepth is used to recover the PC, although all current
164// calls of Output use the call depth 2. Access to the function is serialized.
165func (l *Logger) Output(calldepth, noflag int, v ...interface{}) error {
166	now := time.Now()
167	l.mu.Lock()
168	defer l.mu.Unlock()
169	if l.flag&noflag != 0 {
170		return nil
171	}
172	s := fmt.Sprint(v...)
173	return l.output(calldepth+1, now, s)
174}
175
176// Outputf works like output but formats the output like Printf.
177func (l *Logger) Outputf(calldepth int, noflag int, format string, v ...interface{}) error {
178	now := time.Now()
179	l.mu.Lock()
180	defer l.mu.Unlock()
181	if l.flag&noflag != 0 {
182		return nil
183	}
184	s := fmt.Sprintf(format, v...)
185	return l.output(calldepth+1, now, s)
186}
187
188// Outputln works like output but formats the output like Println.
189func (l *Logger) Outputln(calldepth int, noflag int, v ...interface{}) error {
190	now := time.Now()
191	l.mu.Lock()
192	defer l.mu.Unlock()
193	if l.flag&noflag != 0 {
194		return nil
195	}
196	s := fmt.Sprintln(v...)
197	return l.output(calldepth+1, now, s)
198}
199
200// Panic prints the message like Print and calls panic. The printing
201// might be suppressed by the flag Lnopanic.
202func (l *Logger) Panic(v ...interface{}) {
203	l.Output(2, Lnopanic, v...)
204	s := fmt.Sprint(v...)
205	panic(s)
206}
207
208// Panic prints the message like Print and calls panic. The printing
209// might be suppressed by the flag Lnopanic.
210func Panic(v ...interface{}) {
211	std.Output(2, Lnopanic, v...)
212	s := fmt.Sprint(v...)
213	panic(s)
214}
215
216// Panicf prints the message like Printf and calls panic. The printing
217// might be suppressed by the flag Lnopanic.
218func (l *Logger) Panicf(format string, v ...interface{}) {
219	l.Outputf(2, Lnopanic, format, v...)
220	s := fmt.Sprintf(format, v...)
221	panic(s)
222}
223
224// Panicf prints the message like Printf and calls panic. The printing
225// might be suppressed by the flag Lnopanic.
226func Panicf(format string, v ...interface{}) {
227	std.Outputf(2, Lnopanic, format, v...)
228	s := fmt.Sprintf(format, v...)
229	panic(s)
230}
231
232// Panicln prints the message like Println and calls panic. The printing
233// might be suppressed by the flag Lnopanic.
234func (l *Logger) Panicln(v ...interface{}) {
235	l.Outputln(2, Lnopanic, v...)
236	s := fmt.Sprintln(v...)
237	panic(s)
238}
239
240// Panicln prints the message like Println and calls panic. The printing
241// might be suppressed by the flag Lnopanic.
242func Panicln(v ...interface{}) {
243	std.Outputln(2, Lnopanic, v...)
244	s := fmt.Sprintln(v...)
245	panic(s)
246}
247
248// Fatal prints the message like Print and calls os.Exit(1). The
249// printing might be suppressed by the flag Lnofatal.
250func (l *Logger) Fatal(v ...interface{}) {
251	l.Output(2, Lnofatal, v...)
252	os.Exit(1)
253}
254
255// Fatal prints the message like Print and calls os.Exit(1). The
256// printing might be suppressed by the flag Lnofatal.
257func Fatal(v ...interface{}) {
258	std.Output(2, Lnofatal, v...)
259	os.Exit(1)
260}
261
262// Fatalf prints the message like Printf and calls os.Exit(1). The
263// printing might be suppressed by the flag Lnofatal.
264func (l *Logger) Fatalf(format string, v ...interface{}) {
265	l.Outputf(2, Lnofatal, format, v...)
266	os.Exit(1)
267}
268
269// Fatalf prints the message like Printf and calls os.Exit(1). The
270// printing might be suppressed by the flag Lnofatal.
271func Fatalf(format string, v ...interface{}) {
272	std.Outputf(2, Lnofatal, format, v...)
273	os.Exit(1)
274}
275
276// Fatalln prints the message like Println and calls os.Exit(1). The
277// printing might be suppressed by the flag Lnofatal.
278func (l *Logger) Fatalln(format string, v ...interface{}) {
279	l.Outputln(2, Lnofatal, v...)
280	os.Exit(1)
281}
282
283// Fatalln prints the message like Println and calls os.Exit(1). The
284// printing might be suppressed by the flag Lnofatal.
285func Fatalln(format string, v ...interface{}) {
286	std.Outputln(2, Lnofatal, v...)
287	os.Exit(1)
288}
289
290// Warn prints the message like Print. The printing might be suppressed
291// by the flag Lnowarn.
292func (l *Logger) Warn(v ...interface{}) {
293	l.Output(2, Lnowarn, v...)
294}
295
296// Warn prints the message like Print. The printing might be suppressed
297// by the flag Lnowarn.
298func Warn(v ...interface{}) {
299	std.Output(2, Lnowarn, v...)
300}
301
302// Warnf prints the message like Printf. The printing might be suppressed
303// by the flag Lnowarn.
304func (l *Logger) Warnf(format string, v ...interface{}) {
305	l.Outputf(2, Lnowarn, format, v...)
306}
307
308// Warnf prints the message like Printf. The printing might be suppressed
309// by the flag Lnowarn.
310func Warnf(format string, v ...interface{}) {
311	std.Outputf(2, Lnowarn, format, v...)
312}
313
314// Warnln prints the message like Println. The printing might be suppressed
315// by the flag Lnowarn.
316func (l *Logger) Warnln(v ...interface{}) {
317	l.Outputln(2, Lnowarn, v...)
318}
319
320// Warnln prints the message like Println. The printing might be suppressed
321// by the flag Lnowarn.
322func Warnln(v ...interface{}) {
323	std.Outputln(2, Lnowarn, v...)
324}
325
326// Print prints the message like fmt.Print. The printing might be suppressed
327// by the flag Lnoprint.
328func (l *Logger) Print(v ...interface{}) {
329	l.Output(2, Lnoprint, v...)
330}
331
332// Print prints the message like fmt.Print. The printing might be suppressed
333// by the flag Lnoprint.
334func Print(v ...interface{}) {
335	std.Output(2, Lnoprint, v...)
336}
337
338// Printf prints the message like fmt.Printf. The printing might be suppressed
339// by the flag Lnoprint.
340func (l *Logger) Printf(format string, v ...interface{}) {
341	l.Outputf(2, Lnoprint, format, v...)
342}
343
344// Printf prints the message like fmt.Printf. The printing might be suppressed
345// by the flag Lnoprint.
346func Printf(format string, v ...interface{}) {
347	std.Outputf(2, Lnoprint, format, v...)
348}
349
350// Println prints the message like fmt.Println. The printing might be
351// suppressed by the flag Lnoprint.
352func (l *Logger) Println(v ...interface{}) {
353	l.Outputln(2, Lnoprint, v...)
354}
355
356// Println prints the message like fmt.Println. The printing might be
357// suppressed by the flag Lnoprint.
358func Println(v ...interface{}) {
359	std.Outputln(2, Lnoprint, v...)
360}
361
362// Debug prints the message like Print. The printing might be suppressed
363// by the flag Lnodebug.
364func (l *Logger) Debug(v ...interface{}) {
365	l.Output(2, Lnodebug, v...)
366}
367
368// Debug prints the message like Print. The printing might be suppressed
369// by the flag Lnodebug.
370func Debug(v ...interface{}) {
371	std.Output(2, Lnodebug, v...)
372}
373
374// Debugf prints the message like Printf. The printing might be suppressed
375// by the flag Lnodebug.
376func (l *Logger) Debugf(format string, v ...interface{}) {
377	l.Outputf(2, Lnodebug, format, v...)
378}
379
380// Debugf prints the message like Printf. The printing might be suppressed
381// by the flag Lnodebug.
382func Debugf(format string, v ...interface{}) {
383	std.Outputf(2, Lnodebug, format, v...)
384}
385
386// Debugln prints the message like Println. The printing might be suppressed
387// by the flag Lnodebug.
388func (l *Logger) Debugln(v ...interface{}) {
389	l.Outputln(2, Lnodebug, v...)
390}
391
392// Debugln prints the message like Println. The printing might be suppressed
393// by the flag Lnodebug.
394func Debugln(v ...interface{}) {
395	std.Outputln(2, Lnodebug, v...)
396}
397
398// Flags returns the current flags used by the logger.
399func (l *Logger) Flags() int {
400	l.mu.Lock()
401	defer l.mu.Unlock()
402	return l.flag
403}
404
405// Flags returns the current flags used by the standard logger.
406func Flags() int {
407	return std.Flags()
408}
409
410// SetFlags sets the flags of the logger.
411func (l *Logger) SetFlags(flag int) {
412	l.mu.Lock()
413	defer l.mu.Unlock()
414	l.flag = flag
415}
416
417// SetFlags sets the flags for the standard logger.
418func SetFlags(flag int) {
419	std.SetFlags(flag)
420}
421
422// Prefix returns the prefix used by the logger.
423func (l *Logger) Prefix() string {
424	l.mu.Lock()
425	defer l.mu.Unlock()
426	return l.prefix
427}
428
429// Prefix returns the prefix used by the standard logger of the package.
430func Prefix() string {
431	return std.Prefix()
432}
433
434// SetPrefix sets the prefix for the logger.
435func (l *Logger) SetPrefix(prefix string) {
436	l.mu.Lock()
437	defer l.mu.Unlock()
438	l.prefix = prefix
439}
440
441// SetPrefix sets the prefix of the standard logger of the package.
442func SetPrefix(prefix string) {
443	std.SetPrefix(prefix)
444}
445
446// SetOutput sets the output of the logger.
447func (l *Logger) SetOutput(w io.Writer) {
448	l.mu.Lock()
449	defer l.mu.Unlock()
450	l.out = w
451}
452
453// SetOutput sets the output for the standard logger of the package.
454func SetOutput(w io.Writer) {
455	std.SetOutput(w)
456}