Logger 核心结构

Logger - 图1

Logger

  1. type Logger struct {
  2. core zapcore.Core
  3. development bool
  4. name string
  5. errorOutput zapcore.WriteSyncer
  6. addCaller bool
  7. addStack zapcore.LevelEnabler
  8. callerSkip int
  9. }

zapcore

  • Core
  1. type Core interface {
  2. LevelEnabler
  3. With([]Field) Core
  4. Check(Entry, *CheckedEntry) *CheckedEntry
  5. Write(Entry, []Field) error
  6. Sync() error
  7. }
  • WriteSyncer
  1. type WriteSyncer interface {
  2. io.Writer
  3. Sync() error
  4. }
  • LevelEnabler
  1. type LevelEnabler interface {
  2. Enabled(Level) bool
  3. }

创建 Logger

通过 zapcore.Core 创建

  1. func New(core zapcore.Core, options ...Option) *Logger {
  2. if core == nil {
  3. return NewNop()
  4. }
  5. log := &Logger{
  6. core: core,
  7. errorOutput: zapcore.Lock(os.Stderr),
  8. addStack: zapcore.FatalLevel + 1,
  9. }
  10. return log.WithOptions(options...)
  11. }

Config 创建

  • Config
  1. type Config struct {
  2. // Level is the minimum enabled logging level. Note that this is a dynamic
  3. // level, so calling Config.Level.SetLevel will atomically change the log
  4. // level of all loggers descended from this config.
  5. Level AtomicLevel `json:"level" yaml:"level"`
  6. // Development puts the logger in development mode, which changes the
  7. // behavior of DPanicLevel and takes stacktraces more liberally.
  8. Development bool `json:"development" yaml:"development"`
  9. // DisableCaller stops annotating logs with the calling function's file
  10. // name and line number. By default, all logs are annotated.
  11. DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
  12. // DisableStacktrace completely disables automatic stacktrace capturing. By
  13. // default, stacktraces are captured for WarnLevel and above logs in
  14. // development and ErrorLevel and above in production.
  15. DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
  16. // Sampling sets a sampling policy. A nil SamplingConfig disables sampling.
  17. Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
  18. // Encoding sets the logger's encoding. Valid values are "json" and
  19. // "console", as well as any third-party encodings registered via
  20. // RegisterEncoder.
  21. Encoding string `json:"encoding" yaml:"encoding"`
  22. // EncoderConfig sets options for the chosen encoder. See
  23. // zapcore.EncoderConfig for details.
  24. EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
  25. // OutputPaths is a list of URLs or file paths to write logging output to.
  26. // See Open for details.
  27. OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
  28. // ErrorOutputPaths is a list of URLs to write internal logger errors to.
  29. // The default is standard error.
  30. //
  31. // Note that this setting only affects internal errors; for sample code that
  32. // sends error-level logs to a different location from info- and debug-level
  33. // logs, see the package-level AdvancedConfiguration example.
  34. ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
  35. // InitialFields is a collection of fields to add to the root logger.
  36. InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
  37. }
  • NewProduction
  1. func NewProduction(options ...Option) (*Logger, error) {
  2. return NewProductionConfig().Build(options...)
  3. }
  • NewDevelopment
  1. func NewDevelopment(options ...Option) (*Logger, error) {
  2. return NewDevelopmentConfig().Build(options...)
  3. }
  • WithOptions
  1. func (log *Logger) WithOptions(opts ...Option) *Logger {
  2. c := log.clone()
  3. for _, opt := range opts {
  4. opt.apply(c)
  5. }
  6. return c
  7. }
  • With
  1. func (log *Logger) With(fields ...Field) *Logger {
  2. if len(fields) == 0 {
  3. return log
  4. }
  5. l := log.clone()
  6. l.core = l.core.With(fields)
  7. return l
  8. }

记录日志

Info

  1. func (log *Logger) Info(msg string, fields ...Field) {
  2. if ce := log.check(InfoLevel, msg); ce != nil { // 生成 CheckedEntry
  3. ce.Write(fields...)
  4. }
  5. }

check

  1. func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry {
  2. // 跳过的栈帧数
  3. const callerSkipOffset = 2
  4. // 创建 Entry 对象
  5. ent := zapcore.Entry{
  6. LoggerName: log.name,
  7. Time: time.Now(),
  8. Level: lvl,
  9. Message: msg,
  10. }
  11. ce := log.core.Check(ent, nil) // 通过 zapcore.Core 检查,并返回 CheckedEntry
  12. willWrite := ce != nil
  13. // Set up any required terminal behavior.
  14. switch ent.Level {
  15. case zapcore.PanicLevel:
  16. ce = ce.Should(ent, zapcore.WriteThenPanic)
  17. case zapcore.FatalLevel:
  18. ce = ce.Should(ent, zapcore.WriteThenFatal)
  19. case zapcore.DPanicLevel:
  20. if log.development {
  21. ce = ce.Should(ent, zapcore.WriteThenPanic)
  22. }
  23. }
  24. // Only do further annotation if we're going to write this message; checked
  25. // entries that exist only for terminal behavior don't benefit from
  26. // annotation.
  27. if !willWrite {
  28. return ce
  29. }
  30. // Thread the error output through to the CheckedEntry.
  31. ce.ErrorOutput = log.errorOutput
  32. if log.addCaller {
  33. ce.Entry.Caller = zapcore.NewEntryCaller(runtime.Caller(log.callerSkip + callerSkipOffset))
  34. if !ce.Entry.Caller.Defined {
  35. fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC())
  36. log.errorOutput.Sync()
  37. }
  38. }
  39. if log.addStack.Enabled(ce.Entry.Level) {
  40. ce.Entry.Stack = Stack("").String
  41. }
  42. return ce
  43. }