45

[uber-zap/part2]自定义记录器

 5 years ago
source link: https://studygolang.com/articles/19388?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

说明

  • 之前翻译的一个教程(没有备份原地址,梯子被封了)。原地址找到后补上

正文

使用预设的记录器可以节省时间,但如果确定要调整记录器,需要探索自定义记录器的方法

使用zap配置结构体创建记录器

可以使用配置 zap.Config 创建记录器,这是一个结构体,可以使用需要的值填充结构体,然后调用结构体的 .Build() 方法来获取记录器

cfg := zap.Config{...}
logger, err := cfg.Build()

需要注意的是: zap.Config 的结构体没有默认值,至少为zap需要的三个设置提供值

  • encoder : 只需要添加个 Encoding:"XXX" ,使用 json 就会创建一个JSON的encoder,另一个值是 console
  • 可以使用结构 zapcore.EncoderConfig 来自定义encoder(几乎肯定必须这样做,因为默认的不是很好用)
  • level enabler :这是一种接口类型,它允许zap确定是否应显示特定级别的消息。在zap配置结构中,可以使用Level字段中的AtomicLevel包装器提供此类型。
  • sink : 日志的输出目标,可以使用 OutputPaths 字段指定多个输出路径,输出讲发送到所有这些文件。像 stderrstdout 也是可以的

定制encoder

仅仅在配置结构体中设置encoder的类型是不够的,默认情况下, json 仅仅输出日志消息中专门提供的字段。

以下是调用 .Build() 方法时候不会抛出错误的最少配置了

logger, _ := zap.Config{
        Encoding:    "json",
        Level:       zap.NewAtomicLevelAt(zap.DebugLevel),
        OutputPaths: []string{"stdout"},
    }.Build()

    logger.Info("This is an INFO message with fileds", zap.String("region", "us-west"), zap.Int("id", 2))

输出

{"region":"us-west","id":2}

可以看出,日志信息没有打印出来!

要在 json encoder 中添加信息,需要特别指定将在输出中具有此值的 json

logger, _ := zap.Config{
        Encoding:    "json",
        Level:       zap.NewAtomicLevelAt(zap.DebugLevel),
        OutputPaths: []string{"stdout"},
        EncoderConfig: zapcore.EncoderConfig{
            MessageKey: "message", // <---
        },
    }.Build()

    logger.Info("This is an INFO message with fileds", zap.String("region", "us-west"), zap.Int("id", 2))

输出

{"message":"This is an INFO message with fileds","region":"us-west","id":2}

zap 可以像消息中添加更多的元数据,比如: level name , timestamp , caller , stacktrace 等等。除非明确指出与元数据对应的JSON键,否者不会显示。

注意:这些元数据名称必须与encoder匹配,否者zap会出错

示例:

cfg := zap.Config{
        Encoding:         "json",
        Level:            zap.NewAtomicLevelAt(zap.DebugLevel),
        OutputPaths:      []string{"stdout"},
        ErrorOutputPaths: []string{"stderr"},
        EncoderConfig: zapcore.EncoderConfig{
            MessageKey: "message", // <---

            LevelKey:    "level",
            EncodeLevel: zapcore.CapitalLevelEncoder,

            TimeKey:    "time",
            EncodeTime: zapcore.ISO8601TimeEncoder,

            CallerKey:    "caller",
            EncodeCaller: zapcore.ShortCallerEncoder,
        },
    }
    logger, _ := cfg.Build()

    logger.Info("This is an INFO message with fileds", zap.String("region", "us-west"), zap.Int("id", 2))

输出

{"level":"INFO","time":"2018-10-31T14:59:45.238+0800","caller":"zap_config/main.go:29","message":"This is an INFO message with fileds","region":"us-west","id":2}

encoder 元数据字段的其他选项

每个encoder可以根据需要进行定制,以下是zap提供的不同实现

动态改变记录器行为

可以从现有的记录器克隆记录器,并对其行为进行某些修改

  • logger.AddCaller() 添加调用者
  • logger.AddStacktrace() 为给定级别以及以上的消息添加堆栈跟踪
  • logger.Fields() 将指定字段添加到新记录器输出的所有消息中。这种方式相比于在实际日志调用期间指定字段,可以降低内存分配来加快日志记录
  • logger.WrapCore() 允许你修改甚至完全替换记录器中包含的 encoderlevelsink 。以下是示例
fmt.Printf("\n*** Using a JSON encoder, at debug level, sending output tu stuout, all possible keys specified\n\n")

    cfg := zap.Config{
        Encoding:         "json",
        Level:            zap.NewAtomicLevelAt(zapcore.DebugLevel),
        OutputPaths:      []string{"stderr"},
        ErrorOutputPaths: []string{"stderr"},
        EncoderConfig: zapcore.EncoderConfig{
            MessageKey: "message",

            LevelKey:    "level",
            EncodeLevel: zapcore.CapitalLevelEncoder,

            TimeKey:    "time",
            EncodeTime: zapcore.ISO8601TimeEncoder,

            CallerKey:    "caller",
            EncodeCaller: zapcore.ShortCallerEncoder,
        },
    }

    logger, _ := cfg.Build()

    logger.Info("This is an INFO message")

    fmt.Printf("\n*** Same logger with console loggin enable instead\n\n")

    logger.WithOptions(
        zap.WrapCore(
            func(zapcore.Core) zapcore.Core {
                return zapcore.NewCore(zapcore.NewConsoleEncoder(cfg.EncoderConfig), zapcore.AddSync(os.Stderr), zapcore.DebugLevel)
            })).Info("This is an INFO message")

输出

*** Using a JSON encoder, at debug level, sending output tu stuout, all possible keys specified

{"level":"INFO","time":"2018-11-01T08:59:12.984+0800","caller":"wrap_core/main.go:35","message":"This is an INFO message"}

*** Same logger with console loggin enable instead

2018-11-01T08:59:12.984+0800    INFO    wrap_core/main.go:43    This is an INFO message

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK