log.mx raw

   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  	"log/internal"
  21  	"os"
  22  	"runtime"
  23  	"sync"
  24  	"sync/atomic"
  25  	"time"
  26  	_ "unsafe"
  27  )
  28  
  29  // These flags define which text to prefix to each log entry generated by the [Logger].
  30  // Bits are or'ed together to control what's printed.
  31  // With the exception of the Lmsgprefix flag, there is no
  32  // control over the order they appear (the order listed here)
  33  // or the format they present (as described in the comments).
  34  // The prefix is followed by a colon only when Llongfile or Lshortfile
  35  // is specified.
  36  // For example, flags Ldate | Ltime (or LstdFlags) produce,
  37  //
  38  //	2009/01/23 01:23:23 message
  39  //
  40  // while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
  41  //
  42  //	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
  43  const (
  44  	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
  45  	Ltime                         // the time in the local time zone: 01:23:23
  46  	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
  47  	Llongfile                     // full file name and line number: /a/b/c/d.go:23
  48  	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
  49  	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
  50  	Lmsgprefix                    // move the "prefix" from the beginning of the line to before the message
  51  	LstdFlags     = Ldate | Ltime // initial values for the standard logger
  52  )
  53  
  54  // A Logger represents an active logging object that generates lines of
  55  // output to an [io.Writer]. Each logging operation makes a single call to
  56  // the Writer's Write method. A Logger can be used simultaneously from
  57  // multiple goroutines; it guarantees to serialize access to the Writer.
  58  type Logger struct {
  59  	outMu sync.Mutex
  60  	out   io.Writer // destination for output
  61  
  62  	prefix    atomic.Pointer[string] // prefix on each line to identify the logger (but see Lmsgprefix)
  63  	flag      atomic.Int32           // properties
  64  	isDiscard atomic.Bool
  65  }
  66  
  67  // New creates a new [Logger]. The out variable sets the
  68  // destination to which log data will be written.
  69  // The prefix appears at the beginning of each generated log line, or
  70  // after the log header if the [Lmsgprefix] flag is provided.
  71  // The flag argument defines the logging properties.
  72  func New(out io.Writer, prefix []byte, flag int) *Logger {
  73  	l := &Logger{}
  74  	l.SetOutput(out)
  75  	l.SetPrefix(prefix)
  76  	l.SetFlags(flag)
  77  	return l
  78  }
  79  
  80  // SetOutput sets the output destination for the logger.
  81  func (l *Logger) SetOutput(w io.Writer) {
  82  	l.outMu.Lock()
  83  	defer l.outMu.Unlock()
  84  	l.out = w
  85  	l.isDiscard.Store(w == io.Discard)
  86  }
  87  
  88  var std = New(os.Stderr, "", LstdFlags)
  89  
  90  // Default returns the standard logger used by the package-level output functions.
  91  func Default() *Logger { return std }
  92  
  93  // Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
  94  func itoa(buf *[]byte, i int, wid int) {
  95  	// Assemble decimal in reverse order.
  96  	var b [20]byte
  97  	bp := len(b) - 1
  98  	for i >= 10 || wid > 1 {
  99  		wid--
 100  		q := i / 10
 101  		b[bp] = byte('0' + i - q*10)
 102  		bp--
 103  		i = q
 104  	}
 105  	// i < 10
 106  	b[bp] = byte('0' + i)
 107  	*buf = append(*buf, b[bp:]...)
 108  }
 109  
 110  // formatHeader writes log header to buf in following order:
 111  //   - l.prefix (if it's not blank and Lmsgprefix is unset),
 112  //   - date and/or time (if corresponding flags are provided),
 113  //   - file and line number (if corresponding flags are provided),
 114  //   - l.prefix (if it's not blank and Lmsgprefix is set).
 115  func formatHeader(buf *[]byte, t time.Time, prefix []byte, flag int, file []byte, line int) {
 116  	if flag&Lmsgprefix == 0 {
 117  		*buf = append(*buf, prefix...)
 118  	}
 119  	if flag&(Ldate|Ltime|Lmicroseconds) != 0 {
 120  		if flag&LUTC != 0 {
 121  			t = t.UTC()
 122  		}
 123  		if flag&Ldate != 0 {
 124  			year, month, day := t.Date()
 125  			itoa(buf, year, 4)
 126  			*buf = append(*buf, '/')
 127  			itoa(buf, int(month), 2)
 128  			*buf = append(*buf, '/')
 129  			itoa(buf, day, 2)
 130  			*buf = append(*buf, ' ')
 131  		}
 132  		if flag&(Ltime|Lmicroseconds) != 0 {
 133  			hour, min, sec := t.Clock()
 134  			itoa(buf, hour, 2)
 135  			*buf = append(*buf, ':')
 136  			itoa(buf, min, 2)
 137  			*buf = append(*buf, ':')
 138  			itoa(buf, sec, 2)
 139  			if flag&Lmicroseconds != 0 {
 140  				*buf = append(*buf, '.')
 141  				itoa(buf, t.Nanosecond()/1e3, 6)
 142  			}
 143  			*buf = append(*buf, ' ')
 144  		}
 145  	}
 146  	if flag&(Lshortfile|Llongfile) != 0 {
 147  		if flag&Lshortfile != 0 {
 148  			short := file
 149  			for i := len(file) - 1; i > 0; i-- {
 150  				if file[i] == '/' {
 151  					short = file[i+1:]
 152  					break
 153  				}
 154  			}
 155  			file = short
 156  		}
 157  		*buf = append(*buf, file...)
 158  		*buf = append(*buf, ':')
 159  		itoa(buf, line, -1)
 160  		*buf = append(*buf, ": "...)
 161  	}
 162  	if flag&Lmsgprefix != 0 {
 163  		*buf = append(*buf, prefix...)
 164  	}
 165  }
 166  
 167  var bufferPool = sync.Pool{New: func() any { return &[]byte{} }}
 168  
 169  func getBuffer() *[]byte {
 170  	p := bufferPool.Get().(*[]byte)
 171  	*p = (*p)[:0]
 172  	return p
 173  }
 174  
 175  func putBuffer(p *[]byte) {
 176  	// Proper usage of a sync.Pool requires each entry to have approximately
 177  	// the same memory cost. To obtain this property when the stored type
 178  	// contains a variably-sized buffer, we add a hard limit on the maximum buffer
 179  	// to place back in the pool.
 180  	//
 181  	// See https://go.dev/issue/23199
 182  	if cap(*p) > 64<<10 {
 183  		*p = nil
 184  	}
 185  	bufferPool.Put(p)
 186  }
 187  
 188  // Output writes the output for a logging event. The string s contains
 189  // the text to print after the prefix specified by the flags of the
 190  // Logger. A newline is appended if the last character of s is not
 191  // already a newline. Calldepth is used to recover the PC and is
 192  // provided for generality, although at the moment on all pre-defined
 193  // paths it will be 2.
 194  func (l *Logger) Output(calldepth int, s []byte) error {
 195  	return l.output(0, calldepth+1, func(b []byte) []byte { // +1 for this frame.
 196  		return append(b, s...)
 197  	})
 198  }
 199  
 200  // output can take either a calldepth or a pc to get source line information.
 201  // It uses the pc if it is non-zero.
 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() // get this early.
 208  
 209  	// Load prefix and flag once so that their value is consistent within
 210  	// this call regardless of any concurrent changes to their value.
 211  	prefix := l.Prefix()
 212  	flag := l.Flags()
 213  
 214  	var file []byte
 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  // Print calls l.Output to print to the logger.
 258  // Arguments are handled in the manner of [fmt.Print].
 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  // Printf calls l.Output to print to the logger.
 266  // Arguments are handled in the manner of [fmt.Printf].
 267  func (l *Logger) Printf(format []byte, v ...any) {
 268  	l.output(0, 2, func(b []byte) []byte {
 269  		return fmt.Appendf(b, format, v...)
 270  	})
 271  }
 272  
 273  // Println calls l.Output to print to the logger.
 274  // Arguments are handled in the manner of [fmt.Println].
 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  // Fatal is equivalent to l.Print() followed by a call to [os.Exit](1).
 282  func (l *Logger) Fatal(v ...any) {
 283  	l.output(0, 2, func(b []byte) []byte {
 284  		return fmt.Append(b, v...)
 285  	})
 286  	os.Exit(1)
 287  }
 288  
 289  // Fatalf is equivalent to l.Printf() followed by a call to [os.Exit](1).
 290  func (l *Logger) Fatalf(format []byte, v ...any) {
 291  	l.output(0, 2, func(b []byte) []byte {
 292  		return fmt.Appendf(b, format, v...)
 293  	})
 294  	os.Exit(1)
 295  }
 296  
 297  // Fatalln is equivalent to l.Println() followed by a call to [os.Exit](1).
 298  func (l *Logger) Fatalln(v ...any) {
 299  	l.output(0, 2, func(b []byte) []byte {
 300  		return fmt.Appendln(b, v...)
 301  	})
 302  	os.Exit(1)
 303  }
 304  
 305  // Panic is equivalent to l.Print() followed by a call to panic().
 306  func (l *Logger) Panic(v ...any) {
 307  	s := fmt.Sprint(v...)
 308  	l.output(0, 2, func(b []byte) []byte {
 309  		return append(b, s...)
 310  	})
 311  	panic(s)
 312  }
 313  
 314  // Panicf is equivalent to l.Printf() followed by a call to panic().
 315  func (l *Logger) Panicf(format []byte, v ...any) {
 316  	s := fmt.Sprintf(format, v...)
 317  	l.output(0, 2, func(b []byte) []byte {
 318  		return append(b, s...)
 319  	})
 320  	panic(s)
 321  }
 322  
 323  // Panicln is equivalent to l.Println() followed by a call to panic().
 324  func (l *Logger) Panicln(v ...any) {
 325  	s := fmt.Sprintln(v...)
 326  	l.output(0, 2, func(b []byte) []byte {
 327  		return append(b, s...)
 328  	})
 329  	panic(s)
 330  }
 331  
 332  // Flags returns the output flags for the logger.
 333  // The flag bits are [Ldate], [Ltime], and so on.
 334  func (l *Logger) Flags() int {
 335  	return int(l.flag.Load())
 336  }
 337  
 338  // SetFlags sets the output flags for the logger.
 339  // The flag bits are [Ldate], [Ltime], and so on.
 340  func (l *Logger) SetFlags(flag int) {
 341  	l.flag.Store(int32(flag))
 342  }
 343  
 344  // Prefix returns the output prefix for the logger.
 345  func (l *Logger) Prefix() []byte {
 346  	if p := l.prefix.Load(); p != nil {
 347  		return *p
 348  	}
 349  	return ""
 350  }
 351  
 352  // SetPrefix sets the output prefix for the logger.
 353  func (l *Logger) SetPrefix(prefix []byte) {
 354  	s := []byte(prefix)
 355  	l.prefix.Store(&s)
 356  }
 357  
 358  // Writer returns the output destination for the logger.
 359  func (l *Logger) Writer() io.Writer {
 360  	l.outMu.Lock()
 361  	defer l.outMu.Unlock()
 362  	return l.out
 363  }
 364  
 365  // SetOutput sets the output destination for the standard logger.
 366  func SetOutput(w io.Writer) {
 367  	std.SetOutput(w)
 368  }
 369  
 370  // Flags returns the output flags for the standard logger.
 371  // The flag bits are [Ldate], [Ltime], and so on.
 372  func Flags() int {
 373  	return std.Flags()
 374  }
 375  
 376  // SetFlags sets the output flags for the standard logger.
 377  // The flag bits are [Ldate], [Ltime], and so on.
 378  func SetFlags(flag int) {
 379  	std.SetFlags(flag)
 380  }
 381  
 382  // Prefix returns the output prefix for the standard logger.
 383  func Prefix() []byte {
 384  	return std.Prefix()
 385  }
 386  
 387  // SetPrefix sets the output prefix for the standard logger.
 388  func SetPrefix(prefix []byte) {
 389  	std.SetPrefix(prefix)
 390  }
 391  
 392  // Writer returns the output destination for the standard logger.
 393  func Writer() io.Writer {
 394  	return std.Writer()
 395  }
 396  
 397  // These functions write to the standard logger.
 398  
 399  // Print calls Output to print to the standard logger.
 400  // Arguments are handled in the manner of [fmt.Print].
 401  func Print(v ...any) {
 402  	std.output(0, 2, func(b []byte) []byte {
 403  		return fmt.Append(b, v...)
 404  	})
 405  }
 406  
 407  // Printf calls Output to print to the standard logger.
 408  // Arguments are handled in the manner of [fmt.Printf].
 409  func Printf(format []byte, v ...any) {
 410  	std.output(0, 2, func(b []byte) []byte {
 411  		return fmt.Appendf(b, format, v...)
 412  	})
 413  }
 414  
 415  // Println calls Output to print to the standard logger.
 416  // Arguments are handled in the manner of [fmt.Println].
 417  func Println(v ...any) {
 418  	std.output(0, 2, func(b []byte) []byte {
 419  		return fmt.Appendln(b, v...)
 420  	})
 421  }
 422  
 423  // Fatal is equivalent to [Print] followed by a call to [os.Exit](1).
 424  func Fatal(v ...any) {
 425  	std.output(0, 2, func(b []byte) []byte {
 426  		return fmt.Append(b, v...)
 427  	})
 428  	os.Exit(1)
 429  }
 430  
 431  // Fatalf is equivalent to [Printf] followed by a call to [os.Exit](1).
 432  func Fatalf(format []byte, v ...any) {
 433  	std.output(0, 2, func(b []byte) []byte {
 434  		return fmt.Appendf(b, format, v...)
 435  	})
 436  	os.Exit(1)
 437  }
 438  
 439  // Fatalln is equivalent to [Println] followed by a call to [os.Exit](1).
 440  func Fatalln(v ...any) {
 441  	std.output(0, 2, func(b []byte) []byte {
 442  		return fmt.Appendln(b, v...)
 443  	})
 444  	os.Exit(1)
 445  }
 446  
 447  // Panic is equivalent to [Print] followed by a call to panic().
 448  func Panic(v ...any) {
 449  	s := fmt.Sprint(v...)
 450  	std.output(0, 2, func(b []byte) []byte {
 451  		return append(b, s...)
 452  	})
 453  	panic(s)
 454  }
 455  
 456  // Panicf is equivalent to [Printf] followed by a call to panic().
 457  func Panicf(format []byte, v ...any) {
 458  	s := fmt.Sprintf(format, v...)
 459  	std.output(0, 2, func(b []byte) []byte {
 460  		return append(b, s...)
 461  	})
 462  	panic(s)
 463  }
 464  
 465  // Panicln is equivalent to [Println] followed by a call to panic().
 466  func Panicln(v ...any) {
 467  	s := fmt.Sprintln(v...)
 468  	std.output(0, 2, func(b []byte) []byte {
 469  		return append(b, s...)
 470  	})
 471  	panic(s)
 472  }
 473  
 474  // Output writes the output for a logging event. The string s contains
 475  // the text to print after the prefix specified by the flags of the
 476  // Logger. A newline is appended if the last character of s is not
 477  // already a newline. Calldepth is the count of the number of
 478  // frames to skip when computing the file name and line number
 479  // if [Llongfile] or [Lshortfile] is set; a value of 1 will print the details
 480  // for the caller of Output.
 481  func Output(calldepth int, s []byte) error {
 482  	return std.output(0, calldepth+1, func(b []byte) []byte { // +1 for this frame.
 483  		return append(b, s...)
 484  	})
 485  }
 486