...

Source file src/log/log.go

Documentation: log

     1  // Copyright 2009 The Go Authors. 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 log implements a simple logging package. It defines a type, Logger,
     6  // with methods for formatting output. It also has a predefined 'standard'
     7  // Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and
     8  // Panic[f|ln], which are easier to use than creating a Logger manually.
     9  // That logger writes to standard error and prints the date and time
    10  // of each logged message.
    11  // Every log message is output on a separate line: if the message being
    12  // printed does not end in a newline, the logger will add one.
    13  // The Fatal functions call os.Exit(1) after writing the log message.
    14  // The Panic functions call panic after writing the log message.
    15  package log
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  	"os"
    21  	"runtime"
    22  	"sync"
    23  	"sync/atomic"
    24  	"time"
    25  )
    26  
    27  // These flags define which text to prefix to each log entry generated by the Logger.
    28  // Bits are or'ed together to control what's printed.
    29  // With the exception of the Lmsgprefix flag, there is no
    30  // control over the order they appear (the order listed here)
    31  // or the format they present (as described in the comments).
    32  // The prefix is followed by a colon only when Llongfile or Lshortfile
    33  // is specified.
    34  // For example, flags Ldate | Ltime (or LstdFlags) produce,
    35  //
    36  //	2009/01/23 01:23:23 message
    37  //
    38  // while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
    39  //
    40  //	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
    41  const (
    42  	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
    43  	Ltime                         // the time in the local time zone: 01:23:23
    44  	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
    45  	Llongfile                     // full file name and line number: /a/b/c/d.go:23
    46  	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
    47  	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
    48  	Lmsgprefix                    // move the "prefix" from the beginning of the line to before the message
    49  	LstdFlags     = Ldate | Ltime // initial values for the standard logger
    50  )
    51  
    52  // A Logger represents an active logging object that generates lines of
    53  // output to an io.Writer. Each logging operation makes a single call to
    54  // the Writer's Write method. A Logger can be used simultaneously from
    55  // multiple goroutines; it guarantees to serialize access to the Writer.
    56  type Logger struct {
    57  	mu        sync.Mutex // ensures atomic writes; protects the following fields
    58  	prefix    string     // prefix on each line to identify the logger (but see Lmsgprefix)
    59  	flag      int        // properties
    60  	out       io.Writer  // destination for output
    61  	buf       []byte     // for accumulating text to write
    62  	isDiscard int32      // atomic boolean: whether out == io.Discard
    63  }
    64  
    65  // New creates a new Logger. The out variable sets the
    66  // destination to which log data will be written.
    67  // The prefix appears at the beginning of each generated log line, or
    68  // after the log header if the Lmsgprefix flag is provided.
    69  // The flag argument defines the logging properties.
    70  func New(out io.Writer, prefix string, flag int) *Logger {
    71  	l := &Logger{out: out, prefix: prefix, flag: flag}
    72  	if out == io.Discard {
    73  		l.isDiscard = 1
    74  	}
    75  	return l
    76  }
    77  
    78  // SetOutput sets the output destination for the logger.
    79  func (l *Logger) SetOutput(w io.Writer) {
    80  	l.mu.Lock()
    81  	defer l.mu.Unlock()
    82  	l.out = w
    83  	isDiscard := int32(0)
    84  	if w == io.Discard {
    85  		isDiscard = 1
    86  	}
    87  	atomic.StoreInt32(&l.isDiscard, isDiscard)
    88  }
    89  
    90  var std = New(os.Stderr, "", LstdFlags)
    91  
    92  // Default returns the standard logger used by the package-level output functions.
    93  func Default() *Logger { return std }
    94  
    95  // Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
    96  func itoa(buf *[]byte, i int, wid int) {
    97  	// Assemble decimal in reverse order.
    98  	var b [20]byte
    99  	bp := len(b) - 1
   100  	for i >= 10 || wid > 1 {
   101  		wid--
   102  		q := i / 10
   103  		b[bp] = byte('0' + i - q*10)
   104  		bp--
   105  		i = q
   106  	}
   107  	// i < 10
   108  	b[bp] = byte('0' + i)
   109  	*buf = append(*buf, b[bp:]...)
   110  }
   111  
   112  // formatHeader writes log header to buf in following order:
   113  //   - l.prefix (if it's not blank and Lmsgprefix is unset),
   114  //   - date and/or time (if corresponding flags are provided),
   115  //   - file and line number (if corresponding flags are provided),
   116  //   - l.prefix (if it's not blank and Lmsgprefix is set).
   117  func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
   118  	if l.flag&Lmsgprefix == 0 {
   119  		*buf = append(*buf, l.prefix...)
   120  	}
   121  	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
   122  		if l.flag&LUTC != 0 {
   123  			t = t.UTC()
   124  		}
   125  		if l.flag&Ldate != 0 {
   126  			year, month, day := t.Date()
   127  			itoa(buf, year, 4)
   128  			*buf = append(*buf, '/')
   129  			itoa(buf, int(month), 2)
   130  			*buf = append(*buf, '/')
   131  			itoa(buf, day, 2)
   132  			*buf = append(*buf, ' ')
   133  		}
   134  		if l.flag&(Ltime|Lmicroseconds) != 0 {
   135  			hour, min, sec := t.Clock()
   136  			itoa(buf, hour, 2)
   137  			*buf = append(*buf, ':')
   138  			itoa(buf, min, 2)
   139  			*buf = append(*buf, ':')
   140  			itoa(buf, sec, 2)
   141  			if l.flag&Lmicroseconds != 0 {
   142  				*buf = append(*buf, '.')
   143  				itoa(buf, t.Nanosecond()/1e3, 6)
   144  			}
   145  			*buf = append(*buf, ' ')
   146  		}
   147  	}
   148  	if l.flag&(Lshortfile|Llongfile) != 0 {
   149  		if l.flag&Lshortfile != 0 {
   150  			short := file
   151  			for i := len(file) - 1; i > 0; i-- {
   152  				if file[i] == '/' {
   153  					short = file[i+1:]
   154  					break
   155  				}
   156  			}
   157  			file = short
   158  		}
   159  		*buf = append(*buf, file...)
   160  		*buf = append(*buf, ':')
   161  		itoa(buf, line, -1)
   162  		*buf = append(*buf, ": "...)
   163  	}
   164  	if l.flag&Lmsgprefix != 0 {
   165  		*buf = append(*buf, l.prefix...)
   166  	}
   167  }
   168  
   169  // Output writes the output for a logging event. The string s contains
   170  // the text to print after the prefix specified by the flags of the
   171  // Logger. A newline is appended if the last character of s is not
   172  // already a newline. Calldepth is used to recover the PC and is
   173  // provided for generality, although at the moment on all pre-defined
   174  // paths it will be 2.
   175  func (l *Logger) Output(calldepth int, s string) error {
   176  	now := time.Now() // get this early.
   177  	var file string
   178  	var line int
   179  	l.mu.Lock()
   180  	defer l.mu.Unlock()
   181  	if l.flag&(Lshortfile|Llongfile) != 0 {
   182  		// Release lock while getting caller info - it's expensive.
   183  		l.mu.Unlock()
   184  		var ok bool
   185  		_, file, line, ok = runtime.Caller(calldepth)
   186  		if !ok {
   187  			file = "???"
   188  			line = 0
   189  		}
   190  		l.mu.Lock()
   191  	}
   192  	l.buf = l.buf[:0]
   193  	l.formatHeader(&l.buf, now, file, line)
   194  	l.buf = append(l.buf, s...)
   195  	if len(s) == 0 || s[len(s)-1] != '\n' {
   196  		l.buf = append(l.buf, '\n')
   197  	}
   198  	_, err := l.out.Write(l.buf)
   199  	return err
   200  }
   201  
   202  // Printf calls l.Output to print to the logger.
   203  // Arguments are handled in the manner of fmt.Printf.
   204  func (l *Logger) Printf(format string, v ...any) {
   205  	if atomic.LoadInt32(&l.isDiscard) != 0 {
   206  		return
   207  	}
   208  	l.Output(2, fmt.Sprintf(format, v...))
   209  }
   210  
   211  // Print calls l.Output to print to the logger.
   212  // Arguments are handled in the manner of fmt.Print.
   213  func (l *Logger) Print(v ...any) {
   214  	if atomic.LoadInt32(&l.isDiscard) != 0 {
   215  		return
   216  	}
   217  	l.Output(2, fmt.Sprint(v...))
   218  }
   219  
   220  // Println calls l.Output to print to the logger.
   221  // Arguments are handled in the manner of fmt.Println.
   222  func (l *Logger) Println(v ...any) {
   223  	if atomic.LoadInt32(&l.isDiscard) != 0 {
   224  		return
   225  	}
   226  	l.Output(2, fmt.Sprintln(v...))
   227  }
   228  
   229  // Fatal is equivalent to l.Print() followed by a call to os.Exit(1).
   230  func (l *Logger) Fatal(v ...any) {
   231  	l.Output(2, fmt.Sprint(v...))
   232  	os.Exit(1)
   233  }
   234  
   235  // Fatalf is equivalent to l.Printf() followed by a call to os.Exit(1).
   236  func (l *Logger) Fatalf(format string, v ...any) {
   237  	l.Output(2, fmt.Sprintf(format, v...))
   238  	os.Exit(1)
   239  }
   240  
   241  // Fatalln is equivalent to l.Println() followed by a call to os.Exit(1).
   242  func (l *Logger) Fatalln(v ...any) {
   243  	l.Output(2, fmt.Sprintln(v...))
   244  	os.Exit(1)
   245  }
   246  
   247  // Panic is equivalent to l.Print() followed by a call to panic().
   248  func (l *Logger) Panic(v ...any) {
   249  	s := fmt.Sprint(v...)
   250  	l.Output(2, s)
   251  	panic(s)
   252  }
   253  
   254  // Panicf is equivalent to l.Printf() followed by a call to panic().
   255  func (l *Logger) Panicf(format string, v ...any) {
   256  	s := fmt.Sprintf(format, v...)
   257  	l.Output(2, s)
   258  	panic(s)
   259  }
   260  
   261  // Panicln is equivalent to l.Println() followed by a call to panic().
   262  func (l *Logger) Panicln(v ...any) {
   263  	s := fmt.Sprintln(v...)
   264  	l.Output(2, s)
   265  	panic(s)
   266  }
   267  
   268  // Flags returns the output flags for the logger.
   269  // The flag bits are Ldate, Ltime, and so on.
   270  func (l *Logger) Flags() int {
   271  	l.mu.Lock()
   272  	defer l.mu.Unlock()
   273  	return l.flag
   274  }
   275  
   276  // SetFlags sets the output flags for the logger.
   277  // The flag bits are Ldate, Ltime, and so on.
   278  func (l *Logger) SetFlags(flag int) {
   279  	l.mu.Lock()
   280  	defer l.mu.Unlock()
   281  	l.flag = flag
   282  }
   283  
   284  // Prefix returns the output prefix for the logger.
   285  func (l *Logger) Prefix() string {
   286  	l.mu.Lock()
   287  	defer l.mu.Unlock()
   288  	return l.prefix
   289  }
   290  
   291  // SetPrefix sets the output prefix for the logger.
   292  func (l *Logger) SetPrefix(prefix string) {
   293  	l.mu.Lock()
   294  	defer l.mu.Unlock()
   295  	l.prefix = prefix
   296  }
   297  
   298  // Writer returns the output destination for the logger.
   299  func (l *Logger) Writer() io.Writer {
   300  	l.mu.Lock()
   301  	defer l.mu.Unlock()
   302  	return l.out
   303  }
   304  
   305  // SetOutput sets the output destination for the standard logger.
   306  func SetOutput(w io.Writer) {
   307  	std.SetOutput(w)
   308  }
   309  
   310  // Flags returns the output flags for the standard logger.
   311  // The flag bits are Ldate, Ltime, and so on.
   312  func Flags() int {
   313  	return std.Flags()
   314  }
   315  
   316  // SetFlags sets the output flags for the standard logger.
   317  // The flag bits are Ldate, Ltime, and so on.
   318  func SetFlags(flag int) {
   319  	std.SetFlags(flag)
   320  }
   321  
   322  // Prefix returns the output prefix for the standard logger.
   323  func Prefix() string {
   324  	return std.Prefix()
   325  }
   326  
   327  // SetPrefix sets the output prefix for the standard logger.
   328  func SetPrefix(prefix string) {
   329  	std.SetPrefix(prefix)
   330  }
   331  
   332  // Writer returns the output destination for the standard logger.
   333  func Writer() io.Writer {
   334  	return std.Writer()
   335  }
   336  
   337  // These functions write to the standard logger.
   338  
   339  // Print calls Output to print to the standard logger.
   340  // Arguments are handled in the manner of fmt.Print.
   341  func Print(v ...any) {
   342  	if atomic.LoadInt32(&std.isDiscard) != 0 {
   343  		return
   344  	}
   345  	std.Output(2, fmt.Sprint(v...))
   346  }
   347  
   348  // Printf calls Output to print to the standard logger.
   349  // Arguments are handled in the manner of fmt.Printf.
   350  func Printf(format string, v ...any) {
   351  	if atomic.LoadInt32(&std.isDiscard) != 0 {
   352  		return
   353  	}
   354  	std.Output(2, fmt.Sprintf(format, v...))
   355  }
   356  
   357  // Println calls Output to print to the standard logger.
   358  // Arguments are handled in the manner of fmt.Println.
   359  func Println(v ...any) {
   360  	if atomic.LoadInt32(&std.isDiscard) != 0 {
   361  		return
   362  	}
   363  	std.Output(2, fmt.Sprintln(v...))
   364  }
   365  
   366  // Fatal is equivalent to Print() followed by a call to os.Exit(1).
   367  func Fatal(v ...any) {
   368  	std.Output(2, fmt.Sprint(v...))
   369  	os.Exit(1)
   370  }
   371  
   372  // Fatalf is equivalent to Printf() followed by a call to os.Exit(1).
   373  func Fatalf(format string, v ...any) {
   374  	std.Output(2, fmt.Sprintf(format, v...))
   375  	os.Exit(1)
   376  }
   377  
   378  // Fatalln is equivalent to Println() followed by a call to os.Exit(1).
   379  func Fatalln(v ...any) {
   380  	std.Output(2, fmt.Sprintln(v...))
   381  	os.Exit(1)
   382  }
   383  
   384  // Panic is equivalent to Print() followed by a call to panic().
   385  func Panic(v ...any) {
   386  	s := fmt.Sprint(v...)
   387  	std.Output(2, s)
   388  	panic(s)
   389  }
   390  
   391  // Panicf is equivalent to Printf() followed by a call to panic().
   392  func Panicf(format string, v ...any) {
   393  	s := fmt.Sprintf(format, v...)
   394  	std.Output(2, s)
   395  	panic(s)
   396  }
   397  
   398  // Panicln is equivalent to Println() followed by a call to panic().
   399  func Panicln(v ...any) {
   400  	s := fmt.Sprintln(v...)
   401  	std.Output(2, s)
   402  	panic(s)
   403  }
   404  
   405  // Output writes the output for a logging event. The string s contains
   406  // the text to print after the prefix specified by the flags of the
   407  // Logger. A newline is appended if the last character of s is not
   408  // already a newline. Calldepth is the count of the number of
   409  // frames to skip when computing the file name and line number
   410  // if Llongfile or Lshortfile is set; a value of 1 will print the details
   411  // for the caller of Output.
   412  func Output(calldepth int, s string) error {
   413  	return std.Output(calldepth+1, s) // +1 for this frame.
   414  }
   415  

View as plain text