log.go
其实就和 fmt 差不多啦,不过多加了前缀而已。需要加哪些前缀是可以调用者指定的,具体可以看那堆常量 flags 的注释
// src/log/log.go ---- line 16// 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.type Logger struct {mu sync.Mutex // ensures atomic writes; protects the following fieldsprefix string // prefix on each line to identify the logger (but see Lmsgprefix)flag int // propertiesout io.Writer // destination for outputbuf []byte // for accumulating text to write}
有意思的地方是,获取文件名和代码行数是通过 runtime 实现的。也就是下面代码块的第 18 行
// src/log/log.go ---- line 152// 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 (l *Logger) Output(calldepth int, s string) error {now := time.Now() // get this early.var file stringvar line intl.mu.Lock()defer l.mu.Unlock()if l.flag&(Lshortfile|Llongfile) != 0 {// Release lock while getting caller info - it's expensive.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(&l.buf, 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}
当然具体实现还是得到后面看到 runtime 的时候再来深究
