| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- // Copyright 2014-2022 Ulrich Kunitz. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Package xlog provides a simple logging package that allows to disable
- // certain message categories. It defines a type, Logger, with multiple
- // methods for formatting output. The package has also a predefined
- // 'standard' Logger accessible through helper function Print[f|ln],
- // Fatal[f|ln], Panic[f|ln], Warn[f|ln], Print[f|ln] and Debug[f|ln]
- // that are easier to use then creating a Logger manually. That logger
- // writes to standard error and prints the date and time of each logged
- // message, which can be configured using the function SetFlags.
- //
- // The Fatal functions call os.Exit(1) after the message is output
- // unless not suppressed by the flags. The Panic functions call panic
- // after the writing the log message unless suppressed.
- package xlog
- import (
- "fmt"
- "io"
- "os"
- "runtime"
- "sync"
- "time"
- )
- // The flags define what information is prefixed to each log entry
- // generated by the Logger. The Lno* versions allow the suppression of
- // specific output. The bits are or'ed together to control what will be
- // printed. There is no control over the order of the items printed and
- // the format. The full format is:
- //
- // 2009-01-23 01:23:23.123123 /a/b/c/d.go:23: message
- const (
- Ldate = 1 << iota // the date: 2009-01-23
- Ltime // the time: 01:23:23
- Lmicroseconds // microsecond resolution: 01:23:23.123123
- Llongfile // full file name and line number: /a/b/c/d.go:23
- Lshortfile // final file name element and line number: d.go:23
- Lnopanic // suppresses output from Panic[f|ln] but not the panic call
- Lnofatal // suppresses output from Fatal[f|ln] but not the exit
- Lnowarn // suppresses output from Warn[f|ln]
- Lnoprint // suppresses output from Print[f|ln]
- Lnodebug // suppresses output from Debug[f|ln]
- // initial values for the standard logger
- Lstdflags = Ldate | Ltime | Lnodebug
- )
- // A Logger represents an active logging object that generates lines of
- // output to an io.Writer. Each logging operation if not suppressed
- // makes a single call to the Writer's Write method. A Logger can be
- // used simultaneously from multiple goroutines; it guarantees to
- // serialize access to the Writer.
- type Logger struct {
- mu sync.Mutex // ensures atomic writes; and protects the following
- // fields
- prefix string // prefix to write at beginning of each line
- flag int // properties
- out io.Writer // destination for output
- buf []byte // for accumulating text to write
- }
- // New creates a new Logger. The out argument sets the destination to
- // which the log output will be written. The prefix appears at the
- // beginning of each log line. The flag argument defines the logging
- // properties.
- func New(out io.Writer, prefix string, flag int) *Logger {
- return &Logger{out: out, prefix: prefix, flag: flag}
- }
- // std is the standard logger used by the package scope functions.
- var std = New(os.Stderr, "", Lstdflags)
- // itoa converts the integer to ASCII. A negative widths will avoid
- // zero-padding. The function supports only non-negative integers.
- func itoa(buf *[]byte, i int, wid int) {
- var u = uint(i)
- if u == 0 && wid <= 1 {
- *buf = append(*buf, '0')
- return
- }
- var b [32]byte
- bp := len(b)
- for ; u > 0 || wid > 0; u /= 10 {
- bp--
- wid--
- b[bp] = byte(u%10) + '0'
- }
- *buf = append(*buf, b[bp:]...)
- }
- // formatHeader puts the header into the buf field of the buffer.
- func (l *Logger) formatHeader(t time.Time, file string, line int) {
- l.buf = append(l.buf, l.prefix...)
- if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
- if l.flag&Ldate != 0 {
- year, month, day := t.Date()
- itoa(&l.buf, year, 4)
- l.buf = append(l.buf, '-')
- itoa(&l.buf, int(month), 2)
- l.buf = append(l.buf, '-')
- itoa(&l.buf, day, 2)
- l.buf = append(l.buf, ' ')
- }
- if l.flag&(Ltime|Lmicroseconds) != 0 {
- hour, min, sec := t.Clock()
- itoa(&l.buf, hour, 2)
- l.buf = append(l.buf, ':')
- itoa(&l.buf, min, 2)
- l.buf = append(l.buf, ':')
- itoa(&l.buf, sec, 2)
- if l.flag&Lmicroseconds != 0 {
- l.buf = append(l.buf, '.')
- itoa(&l.buf, t.Nanosecond()/1e3, 6)
- }
- l.buf = append(l.buf, ' ')
- }
- }
- if l.flag&(Lshortfile|Llongfile) != 0 {
- if l.flag&Lshortfile != 0 {
- short := file
- for i := len(file) - 1; i > 0; i-- {
- if file[i] == '/' {
- short = file[i+1:]
- break
- }
- }
- file = short
- }
- l.buf = append(l.buf, file...)
- l.buf = append(l.buf, ':')
- itoa(&l.buf, line, -1)
- l.buf = append(l.buf, ": "...)
- }
- }
- func (l *Logger) output(calldepth int, now time.Time, s string) error {
- var file string
- var line int
- if l.flag&(Lshortfile|Llongfile) != 0 {
- l.mu.Unlock()
- var ok bool
- _, file, line, ok = runtime.Caller(calldepth)
- if !ok {
- file = "???"
- line = 0
- }
- l.mu.Lock()
- }
- l.buf = l.buf[:0]
- l.formatHeader(now, file, line)
- l.buf = append(l.buf, s...)
- if len(s) == 0 || s[len(s)-1] != '\n' {
- l.buf = append(l.buf, '\n')
- }
- _, err := l.out.Write(l.buf)
- return err
- }
- // Output writes the string s with the header controlled by the flags to
- // the l.out writer. A newline will be appended if s doesn't end in a
- // newline. Calldepth is used to recover the PC, although all current
- // calls of Output use the call depth 2. Access to the function is serialized.
- func (l *Logger) Output(calldepth, noflag int, v ...interface{}) error {
- now := time.Now()
- l.mu.Lock()
- defer l.mu.Unlock()
- if l.flag&noflag != 0 {
- return nil
- }
- s := fmt.Sprint(v...)
- return l.output(calldepth+1, now, s)
- }
- // Outputf works like output but formats the output like Printf.
- func (l *Logger) Outputf(calldepth int, noflag int, format string, v ...interface{}) error {
- now := time.Now()
- l.mu.Lock()
- defer l.mu.Unlock()
- if l.flag&noflag != 0 {
- return nil
- }
- s := fmt.Sprintf(format, v...)
- return l.output(calldepth+1, now, s)
- }
- // Outputln works like output but formats the output like Println.
- func (l *Logger) Outputln(calldepth int, noflag int, v ...interface{}) error {
- now := time.Now()
- l.mu.Lock()
- defer l.mu.Unlock()
- if l.flag&noflag != 0 {
- return nil
- }
- s := fmt.Sprintln(v...)
- return l.output(calldepth+1, now, s)
- }
- // Panic prints the message like Print and calls panic. The printing
- // might be suppressed by the flag Lnopanic.
- func (l *Logger) Panic(v ...interface{}) {
- l.Output(2, Lnopanic, v...)
- s := fmt.Sprint(v...)
- panic(s)
- }
- // Panic prints the message like Print and calls panic. The printing
- // might be suppressed by the flag Lnopanic.
- func Panic(v ...interface{}) {
- std.Output(2, Lnopanic, v...)
- s := fmt.Sprint(v...)
- panic(s)
- }
- // Panicf prints the message like Printf and calls panic. The printing
- // might be suppressed by the flag Lnopanic.
- func (l *Logger) Panicf(format string, v ...interface{}) {
- l.Outputf(2, Lnopanic, format, v...)
- s := fmt.Sprintf(format, v...)
- panic(s)
- }
- // Panicf prints the message like Printf and calls panic. The printing
- // might be suppressed by the flag Lnopanic.
- func Panicf(format string, v ...interface{}) {
- std.Outputf(2, Lnopanic, format, v...)
- s := fmt.Sprintf(format, v...)
- panic(s)
- }
- // Panicln prints the message like Println and calls panic. The printing
- // might be suppressed by the flag Lnopanic.
- func (l *Logger) Panicln(v ...interface{}) {
- l.Outputln(2, Lnopanic, v...)
- s := fmt.Sprintln(v...)
- panic(s)
- }
- // Panicln prints the message like Println and calls panic. The printing
- // might be suppressed by the flag Lnopanic.
- func Panicln(v ...interface{}) {
- std.Outputln(2, Lnopanic, v...)
- s := fmt.Sprintln(v...)
- panic(s)
- }
- // Fatal prints the message like Print and calls os.Exit(1). The
- // printing might be suppressed by the flag Lnofatal.
- func (l *Logger) Fatal(v ...interface{}) {
- l.Output(2, Lnofatal, v...)
- os.Exit(1)
- }
- // Fatal prints the message like Print and calls os.Exit(1). The
- // printing might be suppressed by the flag Lnofatal.
- func Fatal(v ...interface{}) {
- std.Output(2, Lnofatal, v...)
- os.Exit(1)
- }
- // Fatalf prints the message like Printf and calls os.Exit(1). The
- // printing might be suppressed by the flag Lnofatal.
- func (l *Logger) Fatalf(format string, v ...interface{}) {
- l.Outputf(2, Lnofatal, format, v...)
- os.Exit(1)
- }
- // Fatalf prints the message like Printf and calls os.Exit(1). The
- // printing might be suppressed by the flag Lnofatal.
- func Fatalf(format string, v ...interface{}) {
- std.Outputf(2, Lnofatal, format, v...)
- os.Exit(1)
- }
- // Fatalln prints the message like Println and calls os.Exit(1). The
- // printing might be suppressed by the flag Lnofatal.
- func (l *Logger) Fatalln(format string, v ...interface{}) {
- l.Outputln(2, Lnofatal, v...)
- os.Exit(1)
- }
- // Fatalln prints the message like Println and calls os.Exit(1). The
- // printing might be suppressed by the flag Lnofatal.
- func Fatalln(format string, v ...interface{}) {
- std.Outputln(2, Lnofatal, v...)
- os.Exit(1)
- }
- // Warn prints the message like Print. The printing might be suppressed
- // by the flag Lnowarn.
- func (l *Logger) Warn(v ...interface{}) {
- l.Output(2, Lnowarn, v...)
- }
- // Warn prints the message like Print. The printing might be suppressed
- // by the flag Lnowarn.
- func Warn(v ...interface{}) {
- std.Output(2, Lnowarn, v...)
- }
- // Warnf prints the message like Printf. The printing might be suppressed
- // by the flag Lnowarn.
- func (l *Logger) Warnf(format string, v ...interface{}) {
- l.Outputf(2, Lnowarn, format, v...)
- }
- // Warnf prints the message like Printf. The printing might be suppressed
- // by the flag Lnowarn.
- func Warnf(format string, v ...interface{}) {
- std.Outputf(2, Lnowarn, format, v...)
- }
- // Warnln prints the message like Println. The printing might be suppressed
- // by the flag Lnowarn.
- func (l *Logger) Warnln(v ...interface{}) {
- l.Outputln(2, Lnowarn, v...)
- }
- // Warnln prints the message like Println. The printing might be suppressed
- // by the flag Lnowarn.
- func Warnln(v ...interface{}) {
- std.Outputln(2, Lnowarn, v...)
- }
- // Print prints the message like fmt.Print. The printing might be suppressed
- // by the flag Lnoprint.
- func (l *Logger) Print(v ...interface{}) {
- l.Output(2, Lnoprint, v...)
- }
- // Print prints the message like fmt.Print. The printing might be suppressed
- // by the flag Lnoprint.
- func Print(v ...interface{}) {
- std.Output(2, Lnoprint, v...)
- }
- // Printf prints the message like fmt.Printf. The printing might be suppressed
- // by the flag Lnoprint.
- func (l *Logger) Printf(format string, v ...interface{}) {
- l.Outputf(2, Lnoprint, format, v...)
- }
- // Printf prints the message like fmt.Printf. The printing might be suppressed
- // by the flag Lnoprint.
- func Printf(format string, v ...interface{}) {
- std.Outputf(2, Lnoprint, format, v...)
- }
- // Println prints the message like fmt.Println. The printing might be
- // suppressed by the flag Lnoprint.
- func (l *Logger) Println(v ...interface{}) {
- l.Outputln(2, Lnoprint, v...)
- }
- // Println prints the message like fmt.Println. The printing might be
- // suppressed by the flag Lnoprint.
- func Println(v ...interface{}) {
- std.Outputln(2, Lnoprint, v...)
- }
- // Debug prints the message like Print. The printing might be suppressed
- // by the flag Lnodebug.
- func (l *Logger) Debug(v ...interface{}) {
- l.Output(2, Lnodebug, v...)
- }
- // Debug prints the message like Print. The printing might be suppressed
- // by the flag Lnodebug.
- func Debug(v ...interface{}) {
- std.Output(2, Lnodebug, v...)
- }
- // Debugf prints the message like Printf. The printing might be suppressed
- // by the flag Lnodebug.
- func (l *Logger) Debugf(format string, v ...interface{}) {
- l.Outputf(2, Lnodebug, format, v...)
- }
- // Debugf prints the message like Printf. The printing might be suppressed
- // by the flag Lnodebug.
- func Debugf(format string, v ...interface{}) {
- std.Outputf(2, Lnodebug, format, v...)
- }
- // Debugln prints the message like Println. The printing might be suppressed
- // by the flag Lnodebug.
- func (l *Logger) Debugln(v ...interface{}) {
- l.Outputln(2, Lnodebug, v...)
- }
- // Debugln prints the message like Println. The printing might be suppressed
- // by the flag Lnodebug.
- func Debugln(v ...interface{}) {
- std.Outputln(2, Lnodebug, v...)
- }
- // Flags returns the current flags used by the logger.
- func (l *Logger) Flags() int {
- l.mu.Lock()
- defer l.mu.Unlock()
- return l.flag
- }
- // Flags returns the current flags used by the standard logger.
- func Flags() int {
- return std.Flags()
- }
- // SetFlags sets the flags of the logger.
- func (l *Logger) SetFlags(flag int) {
- l.mu.Lock()
- defer l.mu.Unlock()
- l.flag = flag
- }
- // SetFlags sets the flags for the standard logger.
- func SetFlags(flag int) {
- std.SetFlags(flag)
- }
- // Prefix returns the prefix used by the logger.
- func (l *Logger) Prefix() string {
- l.mu.Lock()
- defer l.mu.Unlock()
- return l.prefix
- }
- // Prefix returns the prefix used by the standard logger of the package.
- func Prefix() string {
- return std.Prefix()
- }
- // SetPrefix sets the prefix for the logger.
- func (l *Logger) SetPrefix(prefix string) {
- l.mu.Lock()
- defer l.mu.Unlock()
- l.prefix = prefix
- }
- // SetPrefix sets the prefix of the standard logger of the package.
- func SetPrefix(prefix string) {
- std.SetPrefix(prefix)
- }
- // SetOutput sets the output of the logger.
- func (l *Logger) SetOutput(w io.Writer) {
- l.mu.Lock()
- defer l.mu.Unlock()
- l.out = w
- }
- // SetOutput sets the output for the standard logger of the package.
- func SetOutput(w io.Writer) {
- std.SetOutput(w)
- }
|