golang使用Zap日志库

1. 为什么使用zap

因为它很快,而且我写不出比他更快的日志库😭

当然他还有其他优点,比如:它同时提供了结构化日志记录和printf风格的日志记录

2. 安装zap

go get -u go.uber.org/zap

3. 配置zap

zap提供两种日志记录器,如下表

名称 优点 缺点 Sugared Logger 支持结构化和printf风格的日志记录 较Logger慢 Logger 较Sugared Logger快 只支持强类型的结构化日志记录

  • 创建Logger
  • zap.NewProduction()
  • zap.NewDevelopment()
  • zap.Example()
  • 上述函数均可创建Logger只是输出信息不同
  • 默认情况下日志会打印到控制台

举个例子

package main

import "go.uber.org/zap"

var logger *zap.Logger

func ProductionLogger(){
    logger,_ = zap.NewProduction()
    logger.Info("log info")
}

func DevelopmentLogger(){
    logger,_ = zap.NewDevelopment()
    logger.Info("log info")
}

func ExampleLogger(){
    logger = zap.NewExample()
    logger.Info("log info")
}

func main() {
    ProductionLogger()
    DevelopmentLogger()
    ExampleLogger()
}

运行结果

{"level":"info","ts":1594976812.8990078,"caller":"go_zap/main.go:9","msg":"log info"}
2020-07-17T17:06:52.899+0800    INFO    go_zap/main.go:14   log info
{"level":"info","msg":"log info"}

除DevelopmentLogger之外其余都是json格式输出

  • 创建Sugared Logger
  • 由Logger调用Sugar()方法获得
  • 支持printf风格输出日志

举个例子

package main

import "go.uber.org/zap"

var sugarLogger *zap.SugaredLogger

func ProductionLogger(){
    logger,_ := zap.NewProduction()
    sugarLogger = logger.Sugar()
    sugarLogger.Infof("sugar loger %s", "yes!")
}

func DevelopmentLogger(){
    logger,_ := zap.NewDevelopment()
    sugarLogger = logger.Sugar()
    sugarLogger.Infof("sugar loger %s", "yes!")
}

func ExampleLogger(){
    logger := zap.NewExample()
    sugarLogger = logger.Sugar()
    sugarLogger.Infof("sugar loger %s", "yes!")
}

func main() {
    ProductionLogger()
    DevelopmentLogger()
    ExampleLogger()
}

运行结果

{"level":"info","ts":1594977351.4368348,"caller":"go_zap/main.go:10","msg":"sugar loger yes!"}
2020-07-17T17:15:51.436+0800    INFO    go_zap/main.go:16   sugar loger yes!

{"level":"info","msg":"sugar loger yes!"}

输出结果和Logger类似,但是sugarLogger支持printf

4. 定制Logger

上面所介绍到的三个创建Logger的方法包含了一些预置的配置,如果我们想要完全自定义,那我们就需要自己写好自己需要的配置。

这些配置将被赋值给 zap.Config结构体,然后这个结构体对象调用 Build方法构造Logger,大概就像这样

config := zap.Config{
    ...

}

log, err := config.Build()
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"
}

我们需要特别注意的是 EncoderConfig这个字段,它定义了我们输出的格式,根据他的提示我们来看看 zapcore.EncoderConfig结构体

// 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"
}

这些字段都不难理解,让我们来写一个例子吧

一般情况下我们都是用SugaredLogger因为它的速度足够快,而其功能更加强大,如果呢不知道该怎么选择不如就把两个都选上吧,就像这样

package main

import (
    "go.uber.org/zap"
    "go.uber.org/zap/zapcore"
)

var Logger *zap.Logger
var SugarLogger *zap.SugaredLogger

func Init() error{
    var err error
    // 构造EncoderConfig
    encoderConfig := zapcore.EncoderConfig{
        TimeKey: "timestamp",
        LevelKey: "severity",
        NameKey: "logger",
        CallerKey: "caller",
        MessageKey: "message",
        StacktraceKey: "stacktrace",
        LineEnding: "\n",
        EncodeLevel: zapcore.LowercaseLevelEncoder,
        EncodeTime: zapcore.ISO8601TimeEncoder,
        EncodeDuration: zapcore.SecondsDurationEncoder,
        EncodeCaller:   zapcore.FullCallerEncoder,
    }

    // 构造 Config
    config := zap.Config{
        Level: zap.NewAtomicLevelAt(zapcore.DebugLevel),
        Development: true,
        Encoding: "json",
        EncoderConfig: encoderConfig,
        InitialFields: map[string]interface{}{"MyName": "kainhuck"},
        OutputPaths: []string{"stdout"},
        ErrorOutputPaths: []string{"stdout"},
    }

    // 可以构造Logger了
    Logger, err = config.Build()
    if err != nil {
        return err
    }

    // 然后是SugarLogger
    SugarLogger = Logger.Sugar()
    return nil
}

func main(){
    err := Init()
    if err != nil {
        panic(err)
    }

    SugarLogger.Debugf("ohhhhhhh err:%s", "horika")
}

运行结果

{"severity":"debug","timestamp":"2020-07-17T17:58:56.626+0800","caller":"D:/Coding/go_module/go_zap/main.go:56","message":"ohhhhhhh err:horika","MyName":"kainhuck"}

Original: https://www.cnblogs.com/kainhuck/p/13333765.html
Author: KainHuck
Title: golang使用Zap日志库

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/564414/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球