// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package log implements a simple logging package. It defines a type, [Logger],// with methods for formatting output. It also has a predefined 'standard'// Logger accessible through helper functions Print[f|ln], Fatal[f|ln], and// Panic[f|ln], which are easier to use than creating a Logger manually.// That logger writes to standard error and prints the date and time// of each logged message.// Every log message is output on a separate line: if the message being// printed does not end in a newline, the logger will add one.// The Fatal functions call [os.Exit](1) after writing the log message.// The Panic functions call panic after writing the log message.
package logimport ()// These flags define which text to prefix to each log entry generated by the [Logger].// Bits are or'ed together to control what's printed.// With the exception of the Lmsgprefix flag, there is no// control over the order they appear (the order listed here)// or the format they present (as described in the comments).// The prefix is followed by a colon only when Llongfile or Lshortfile// is specified.// For example, flags Ldate | Ltime (or LstdFlags) produce,//// 2009/01/23 01:23:23 message//// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,//// 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: messageconst (Ldate = 1 << iota// the date in the local time zone: 2009/01/23Ltime// the time in the local time zone: 01:23:23Lmicroseconds// microsecond resolution: 01:23:23.123123. assumes Ltime.Llongfile// full file name and line number: /a/b/c/d.go:23Lshortfile// final file name element and line number: d.go:23. overrides LlongfileLUTC// if Ldate or Ltime is set, use UTC rather than the local time zoneLmsgprefix// move the "prefix" from the beginning of the line to before the messageLstdFlags = Ldate | Ltime// initial values for the standard logger)// A Logger represents an active logging object that generates lines of// output to an [io.Writer]. Each logging operation 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.typeLoggerstruct { outMu sync.Mutex out io.Writer// destination for output prefix atomic.Pointer[string] // prefix on each line to identify the logger (but see Lmsgprefix) flag atomic.Int32// properties isDiscard atomic.Bool}// New creates a new [Logger]. The out variable sets the// destination to which log data will be written.// The prefix appears at the beginning of each generated log line, or// after the log header if the [Lmsgprefix] flag is provided.// The flag argument defines the logging properties.func ( io.Writer, string, int) *Logger { := new(Logger) .SetOutput() .SetPrefix() .SetFlags()return}// SetOutput sets the output destination for the logger.func ( *Logger) ( io.Writer) { .outMu.Lock()defer .outMu.Unlock() .out = .isDiscard.Store( == io.Discard)}var std = New(os.Stderr, "", LstdFlags)// Default returns the standard logger used by the package-level output functions.func () *Logger { returnstd }// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.func itoa( *[]byte, int, int) {// Assemble decimal in reverse order.var [20]byte := len() - 1for >= 10 || > 1 { -- := / 10 [] = byte('0' + - *10) -- = }// i < 10 [] = byte('0' + ) * = append(*, [:]...)}// formatHeader writes log header to buf in following order:// - l.prefix (if it's not blank and Lmsgprefix is unset),// - date and/or time (if corresponding flags are provided),// - file and line number (if corresponding flags are provided),// - l.prefix (if it's not blank and Lmsgprefix is set).func formatHeader( *[]byte, time.Time, string, int, string, int) {if &Lmsgprefix == 0 { * = append(*, ...) }if &(Ldate|Ltime|Lmicroseconds) != 0 {if &LUTC != 0 { = .UTC() }if &Ldate != 0 { , , := .Date()itoa(, , 4) * = append(*, '/')itoa(, int(), 2) * = append(*, '/')itoa(, , 2) * = append(*, ' ') }if &(Ltime|Lmicroseconds) != 0 { , , := .Clock()itoa(, , 2) * = append(*, ':')itoa(, , 2) * = append(*, ':')itoa(, , 2)if &Lmicroseconds != 0 { * = append(*, '.')itoa(, .Nanosecond()/1e3, 6) } * = append(*, ' ') } }if &(Lshortfile|Llongfile) != 0 {if &Lshortfile != 0 { := for := len() - 1; > 0; -- {if [] == '/' { = [+1:]break } } = } * = append(*, ...) * = append(*, ':')itoa(, , -1) * = append(*, ": "...) }if &Lmsgprefix != 0 { * = append(*, ...) }}var bufferPool = sync.Pool{New: func() any { returnnew([]byte) }}func getBuffer() *[]byte { := bufferPool.Get().(*[]byte) * = (*)[:0]return}func putBuffer( *[]byte) {// Proper usage of a sync.Pool requires each entry to have approximately // the same memory cost. To obtain this property when the stored type // contains a variably-sized buffer, we add a hard limit on the maximum buffer // to place back in the pool. // // See https://go.dev/issue/23199ifcap(*) > 64<<10 { * = nil }bufferPool.Put()}// Output writes the output for a logging event. The string s contains// the text to print after the prefix specified by the flags of the// Logger. A newline is appended if the last character of s is not// already a newline. Calldepth is used to recover the PC and is// provided for generality, although at the moment on all pre-defined// paths it will be 2.func ( *Logger) ( int, string) error {return .output(0, +1, func( []byte) []byte { // +1 for this frame.returnappend(, ...) })}// output can take either a calldepth or a pc to get source line information.// It uses the pc if it is non-zero.func ( *Logger) ( uintptr, int, func([]byte) []byte) error {if .isDiscard.Load() {returnnil } := time.Now() // get this early.// Load prefix and flag once so that their value is consistent within // this call regardless of any concurrent changes to their value. := .Prefix() := .Flags()varstringvarintif &(Lshortfile|Llongfile) != 0 {if == 0 {varbool _, , , = runtime.Caller()if ! { = "???" = 0 } } else { := runtime.CallersFrames([]uintptr{}) , := .Next() = .Fileif == "" { = "???" } = .Line } } := getBuffer()deferputBuffer()formatHeader(, , , , , ) * = (*)iflen(*) == 0 || (*)[len(*)-1] != '\n' { * = append(*, '\n') } .outMu.Lock()defer .outMu.Unlock() , := .out.Write(*)return}func init() {internal.DefaultOutput = func( uintptr, []byte) error {returnstd.output(, 0, func( []byte) []byte {returnappend(, ...) }) }}// Print calls l.Output to print to the logger.// Arguments are handled in the manner of [fmt.Print].func ( *Logger) ( ...any) { .output(0, 2, func( []byte) []byte {returnfmt.Append(, ...) })}// Printf calls l.Output to print to the logger.// Arguments are handled in the manner of [fmt.Printf].func ( *Logger) ( string, ...any) { .output(0, 2, func( []byte) []byte {returnfmt.Appendf(, , ...) })}// Println calls l.Output to print to the logger.// Arguments are handled in the manner of [fmt.Println].func ( *Logger) ( ...any) { .output(0, 2, func( []byte) []byte {returnfmt.Appendln(, ...) })}// Fatal is equivalent to l.Print() followed by a call to [os.Exit](1).func ( *Logger) ( ...any) { .output(0, 2, func( []byte) []byte {returnfmt.Append(, ...) })os.Exit(1)}// Fatalf is equivalent to l.Printf() followed by a call to [os.Exit](1).func ( *Logger) ( string, ...any) { .output(0, 2, func( []byte) []byte {returnfmt.Appendf(, , ...) })os.Exit(1)}// Fatalln is equivalent to l.Println() followed by a call to [os.Exit](1).func ( *Logger) ( ...any) { .output(0, 2, func( []byte) []byte {returnfmt.Appendln(, ...) })os.Exit(1)}// Panic is equivalent to l.Print() followed by a call to panic().func ( *Logger) ( ...any) { := fmt.Sprint(...) .output(0, 2, func( []byte) []byte {returnappend(, ...) })panic()}// Panicf is equivalent to l.Printf() followed by a call to panic().func ( *Logger) ( string, ...any) { := fmt.Sprintf(, ...) .output(0, 2, func( []byte) []byte {returnappend(, ...) })panic()}// Panicln is equivalent to l.Println() followed by a call to panic().func ( *Logger) ( ...any) { := fmt.Sprintln(...) .output(0, 2, func( []byte) []byte {returnappend(, ...) })panic()}// Flags returns the output flags for the logger.// The flag bits are [Ldate], [Ltime], and so on.func ( *Logger) () int {returnint(.flag.Load())}// SetFlags sets the output flags for the logger.// The flag bits are [Ldate], [Ltime], and so on.func ( *Logger) ( int) { .flag.Store(int32())}// Prefix returns the output prefix for the logger.func ( *Logger) () string {if := .prefix.Load(); != nil {return * }return""}// SetPrefix sets the output prefix for the logger.func ( *Logger) ( string) { .prefix.Store(&)}// Writer returns the output destination for the logger.func ( *Logger) () io.Writer { .outMu.Lock()defer .outMu.Unlock()return .out}// SetOutput sets the output destination for the standard logger.func ( io.Writer) {std.SetOutput()}// Flags returns the output flags for the standard logger.// The flag bits are [Ldate], [Ltime], and so on.func () int {returnstd.Flags()}// SetFlags sets the output flags for the standard logger.// The flag bits are [Ldate], [Ltime], and so on.func ( int) {std.SetFlags()}// Prefix returns the output prefix for the standard logger.func () string {returnstd.Prefix()}// SetPrefix sets the output prefix for the standard logger.func ( string) {std.SetPrefix()}// Writer returns the output destination for the standard logger.func () io.Writer {returnstd.Writer()}// These functions write to the standard logger.// Print calls Output to print to the standard logger.// Arguments are handled in the manner of [fmt.Print].func ( ...any) {std.output(0, 2, func( []byte) []byte {returnfmt.Append(, ...) })}// Printf calls Output to print to the standard logger.// Arguments are handled in the manner of [fmt.Printf].func ( string, ...any) {std.output(0, 2, func( []byte) []byte {returnfmt.Appendf(, , ...) })}// Println calls Output to print to the standard logger.// Arguments are handled in the manner of [fmt.Println].func ( ...any) {std.output(0, 2, func( []byte) []byte {returnfmt.Appendln(, ...) })}// Fatal is equivalent to [Print] followed by a call to [os.Exit](1).func ( ...any) {std.output(0, 2, func( []byte) []byte {returnfmt.Append(, ...) })os.Exit(1)}// Fatalf is equivalent to [Printf] followed by a call to [os.Exit](1).func ( string, ...any) {std.output(0, 2, func( []byte) []byte {returnfmt.Appendf(, , ...) })os.Exit(1)}// Fatalln is equivalent to [Println] followed by a call to [os.Exit](1).func ( ...any) {std.output(0, 2, func( []byte) []byte {returnfmt.Appendln(, ...) })os.Exit(1)}// Panic is equivalent to [Print] followed by a call to panic().func ( ...any) { := fmt.Sprint(...)std.output(0, 2, func( []byte) []byte {returnappend(, ...) })panic()}// Panicf is equivalent to [Printf] followed by a call to panic().func ( string, ...any) { := fmt.Sprintf(, ...)std.output(0, 2, func( []byte) []byte {returnappend(, ...) })panic()}// Panicln is equivalent to [Println] followed by a call to panic().func ( ...any) { := fmt.Sprintln(...)std.output(0, 2, func( []byte) []byte {returnappend(, ...) })panic()}// Output writes the output for a logging event. The string s contains// the text to print after the prefix specified by the flags of the// Logger. A newline is appended if the last character of s is not// already a newline. Calldepth is the count of the number of// frames to skip when computing the file name and line number// if [Llongfile] or [Lshortfile] is set; a value of 1 will print the details// for the caller of Output.func ( int, string) error {returnstd.output(0, +1, func( []byte) []byte { // +1 for this frame.returnappend(, ...) })}
The pages are generated with Goldsv0.7.7-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.