Logger 核心结构
Logger
type Logger struct { core zapcore.Core development bool name string errorOutput zapcore.WriteSyncer addCaller bool addStack zapcore.LevelEnabler callerSkip int}
zapcore
type Core interface { LevelEnabler With([]Field) Core Check(Entry, *CheckedEntry) *CheckedEntry Write(Entry, []Field) error Sync() error}
type WriteSyncer interface { io.Writer Sync() error}
type LevelEnabler interface { Enabled(Level) bool}
创建 Logger
通过 zapcore.Core 创建
func New(core zapcore.Core, options ...Option) *Logger { if core == nil { return NewNop() } log := &Logger{ core: core, errorOutput: zapcore.Lock(os.Stderr), addStack: zapcore.FatalLevel + 1, } return log.WithOptions(options...)}
Config 创建
type Config struct { // Level is the minimum enabled logging level. Note that this is a dynamic // level, so calling Config.Level.SetLevel will atomically change the log // level of all loggers descended from this config. Level AtomicLevel `json:"level" yaml:"level"` // Development puts the logger in development mode, which changes the // behavior of DPanicLevel and takes stacktraces more liberally. Development bool `json:"development" yaml:"development"` // DisableCaller stops annotating logs with the calling function's file // name and line number. By default, all logs are annotated. DisableCaller bool `json:"disableCaller" yaml:"disableCaller"` // DisableStacktrace completely disables automatic stacktrace capturing. By // default, stacktraces are captured for WarnLevel and above logs in // development and ErrorLevel and above in production. DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"` // Sampling sets a sampling policy. A nil SamplingConfig disables sampling. Sampling *SamplingConfig `json:"sampling" yaml:"sampling"` // Encoding sets the logger's encoding. Valid values are "json" and // "console", as well as any third-party encodings registered via // RegisterEncoder. Encoding string `json:"encoding" yaml:"encoding"` // EncoderConfig sets options for the chosen encoder. See // zapcore.EncoderConfig for details. EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"` // OutputPaths is a list of URLs or file paths to write logging output to. // See Open for details. OutputPaths []string `json:"outputPaths" yaml:"outputPaths"` // ErrorOutputPaths is a list of URLs to write internal logger errors to. // The default is standard error. // // Note that this setting only affects internal errors; for sample code that // sends error-level logs to a different location from info- and debug-level // logs, see the package-level AdvancedConfiguration example. ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"` // InitialFields is a collection of fields to add to the root logger. InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`}
func NewProduction(options ...Option) (*Logger, error) { return NewProductionConfig().Build(options...)}
func NewDevelopment(options ...Option) (*Logger, error) { return NewDevelopmentConfig().Build(options...)}
func (log *Logger) WithOptions(opts ...Option) *Logger { c := log.clone() for _, opt := range opts { opt.apply(c) } return c}
func (log *Logger) With(fields ...Field) *Logger { if len(fields) == 0 { return log } l := log.clone() l.core = l.core.With(fields) return l}
记录日志
Info
func (log *Logger) Info(msg string, fields ...Field) { if ce := log.check(InfoLevel, msg); ce != nil { // 生成 CheckedEntry ce.Write(fields...) }}
check
func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { // 跳过的栈帧数 const callerSkipOffset = 2 // 创建 Entry 对象 ent := zapcore.Entry{ LoggerName: log.name, Time: time.Now(), Level: lvl, Message: msg, } ce := log.core.Check(ent, nil) // 通过 zapcore.Core 检查,并返回 CheckedEntry willWrite := ce != nil // Set up any required terminal behavior. switch ent.Level { case zapcore.PanicLevel: ce = ce.Should(ent, zapcore.WriteThenPanic) case zapcore.FatalLevel: ce = ce.Should(ent, zapcore.WriteThenFatal) case zapcore.DPanicLevel: if log.development { ce = ce.Should(ent, zapcore.WriteThenPanic) } } // Only do further annotation if we're going to write this message; checked // entries that exist only for terminal behavior don't benefit from // annotation. if !willWrite { return ce } // Thread the error output through to the CheckedEntry. ce.ErrorOutput = log.errorOutput if log.addCaller { ce.Entry.Caller = zapcore.NewEntryCaller(runtime.Caller(log.callerSkip + callerSkipOffset)) if !ce.Entry.Caller.Defined { fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC()) log.errorOutput.Sync() } } if log.addStack.Enabled(ce.Entry.Level) { ce.Entry.Stack = Stack("").String } return ce}