zap——從Config自定義日誌格式

前言

我們依然從官方示例開始:

logger, _ := zap.NewProduction()
...

NewProduction的代碼如下:

func NewProduction(options ...Option) (*Logger, error) {
    return NewProductionConfig().Build(options...)
}

func NewProductionConfig() Config {
    return Config{
        Level:       NewAtomicLevelAt(InfoLevel),
        Development: false,
        Sampling: &SamplingConfig{
            Initial:    100,
            Thereafter: 100,
        },
        Encoding:         "json",
        EncoderConfig:    NewProductionEncoderConfig(),
        OutputPaths:      []string{"stderr"},
        ErrorOutputPaths: []string{"stderr"},
    }
}

NewProduction通過創建NewProductionConfig,再通過Config Build Logger。NewProductionConfig內設定了日誌的相關格式要求。

Config

從Config的註釋來看:

Config提供了一種聲明性的方式來構造Logger,通過調用New、Options和各種zapcore.WriteSyncer和zapcore.Core的封裝來完成Logger的創建,主要是簡化了調用者Logger的創建過程。注意:Config僅提供了通用的一些配置項,一些不常用的配置項,仍需要直接使用對應的封裝來實現配置的變更。

// Config offers a declarative way to construct a logger. It doesn't do
// anything that can't be done with New, Options, and the various
// zapcore.WriteSyncer and zapcore.Core wrappers, but it's a simpler way to
// toggle common options.
//
// Note that Config intentionally supports only the most common options. More
// unusual logging setups (logging to network connections or message queues,
// splitting output between multiple files, etc.) are possible, but require
// direct use of the zapcore package. For sample code, see the package-level
// BasicConfiguration and AdvancedConfiguration examples.
//
// For an example showing runtime log level changes, see the documentation for
// AtomicLevel.
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.
    // log級別,可以通過Config.Level.SetLevel動態設置
    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.
    // 是否關閉註釋性logs,默認所有logs鬥志註釋性的。
    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.
    // 採樣設置,記錄全局的CPU、IO負載
    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.
    // 支持編碼json或者console
    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"`
}

EncoderConfig是針對Encoding的具體配置項,主要包含如制定特定key的名稱,時間、日期的格式等,指定後這些信息會出現在log中。

注意:如果不指定對應key的name的話,對應key的信息不處理,即不會寫入到文件中,如MessageKey爲空的話,內容主體不處理,即看不到log內容。

// An EncoderConfig allows users to configure the concrete encoders supplied by
// zapcore.
type EncoderConfig struct {
    // Set the keys used for each log entry. If any key is empty, that portion
    // of the entry is omitted.
    MessageKey    string `json:"messageKey" yaml:"messageKey"`
    LevelKey      string `json:"levelKey" yaml:"levelKey"`
    TimeKey       string `json:"timeKey" yaml:"timeKey"`
    NameKey       string `json:"nameKey" yaml:"nameKey"`
    CallerKey     string `json:"callerKey" yaml:"callerKey"`
    StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"`
    LineEnding    string `json:"lineEnding" yaml:"lineEnding"`
    // Configure the primitive representations of common complex types. For
    // example, some users may want all time.Times serialized as floating-point
    // seconds since epoch, while others may prefer ISO8601 strings.
    EncodeLevel    LevelEncoder    `json:"levelEncoder" yaml:"levelEncoder"`
    EncodeTime     TimeEncoder     `json:"timeEncoder" yaml:"timeEncoder"`
    EncodeDuration DurationEncoder `json:"durationEncoder" yaml:"durationEncoder"`
    EncodeCaller   CallerEncoder   `json:"callerEncoder" yaml:"callerEncoder"`
    // Unlike the other primitive type encoders, EncodeName is optional. The
    // zero value falls back to FullNameEncoder.
    EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"`
}

根據以上的瞭解,我們回頭看看NewProductionConfig。

func NewProductionConfig() Config {
    return Config{
        Level:       NewAtomicLevelAt(InfoLevel),//日誌級別INFO
        Development: false,
        Sampling: &SamplingConfig{//採樣設置
            Initial:    100,
            Thereafter: 100,
        },
        Encoding:         "json",//採用json格式
        EncoderConfig:    NewProductionEncoderConfig(),
        OutputPaths:      []string{"stderr"},//輸出到標準錯誤
        ErrorOutputPaths: []string{"stderr"},
    }
}

func NewProductionEncoderConfig() zapcore.EncoderConfig {
    return zapcore.EncoderConfig{
        TimeKey:        "ts",//時間對應的key名
        LevelKey:       "level",//日誌級別對應的key名
        NameKey:        "logger",//logger名對應的key名
        CallerKey:      "caller",//時間對應的key名
        MessageKey:     "msg",//日誌內容對應的key名,此參數必須不爲空,否則日誌主體不處理
        StacktraceKey:  "stacktrace",//棧追蹤的key名
        LineEnding:     zapcore.DefaultLineEnding,//默認換行,即使不設置
        EncodeLevel:    zapcore.LowercaseLevelEncoder,//小寫
        EncodeTime:     zapcore.EpochTimeEncoder,//時間轉爲s
        EncodeDuration: zapcore.SecondsDurationEncoder,//日期轉爲s
        EncodeCaller:   zapcore.ShortCallerEncoder,//記錄調用路徑格式爲package/file:line
    }
}

NewProductionConfig創建的是一個這樣的Config實例:

日誌級別InfoLevel,非開發環境,採樣間隔100s,編碼格式爲json,輸出及錯誤輸出路徑均爲stderr。EncoderConfig中帶key的設置均爲指定對應參數在信息中key名稱即自定義key名,這些值未設置或爲空時不顯示在log中。

示例結果:

{"level":"info","ts":1577697584.997612,"caller":"test/test.go:14","msg":"failed to fetch URL","url":"http://test","attempt":3,"backoff":1}

根據以上對Config的瞭解,我們根據自己的需求,自定義一個config

自定義Config

config: =zap.Config{
            Level:       zap.NewAtomicLevelAt(zap.DebugLevel),
            Development: true,
            Encoding:    "console",
            EncoderConfig: zapcore.EncoderConfig{
                MessageKey: "msg",
            },
            OutputPaths:      []string{"stdout", "./log.txt"},
            ErrorOutputPaths: []string{"stderr"},
        }
l,_ := Config.Build
l.Info("this is a test config")

以上自定義Config表示意思如下:

DebugLevel及以上級別日誌輸出,Development模式,採用console模式編碼及原始格式,僅展示日誌內容,日誌會顯示在標準輸出中及保存在log.txt文件中,內部發生錯誤顯示在標準錯誤中。注意:console模式不會打印key名的,僅打印對應的value。

輸出示例:

this is a test config

需要注意的是:zap中目前並不能自定義這些通用key出現的先後順序,如對順序有要求的話,建議自行對結果進行處理。

總結

本篇主要是對Config進行進一步的說明,並對自定義config進行了示例,後續對創建的過程做說明。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章