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