文档:https://godoc.org/go.uber.org/zap

Zap是非常快的、结构化的,分日志级别的Go日志库。

为什么选择Uber-go zap

  • 它同时提供了结构化日志记录和printf风格的日志记录
  • 它非常的快

根据Uber-go Zap的文档,它的性能比类似的结构化日志包更好——也比标准库更快。 以下是Zap发布的基准测试信息
记录一条消息和10个字段:
image.png
记录一个静态字符串,没有任何上下文或printf风格的模板:
image.png

Constants

  1. const (
  2. DebugLevel = zapcore.DebugLevel
  3. InfoLevel = zapcore.InfoLevel
  4. WarnLevel = zapcore.WarnLevel
  5. ErrorLevel = zapcore.ErrorLevel
  6. DPanicLevel = zapcore.DPanicLevel
  7. PanicLevel = zapcore.PanicLevel
  8. FatalLevel = zapcore.FatalLevel
  9. )

Func

  1. func NewProductionEncoderConfig() zapcore.EncoderConfig
  2. func NewDevelopmentEncoderConfig() zapcore.EncoderConfig

type Logger

  1. type Logger struct {
  2. // contains filtered or unexported fields
  3. }

日志记录器提供快速、分层、结构化的日志记录。所有方法对于并发使用都是安全的。
Logger是为每一微秒和每一次分配都很重要的上下文设计的,因此它的API有意地倾向于性能和类型安全而不是简洁。对于大多数应用程序,SugaredLogger在性能和易用之间实现了更好的平衡。

func L() Logger
func New(core zapcore.Core, options …Option)
Logger
func NewDevelopment(options …Option) (*Logger, error)

  • 级别是DebugLevel,标准格式化输出,使用的是NewDevelopmentConfig

func NewProduction(options …Option) (*Logger, error)

  • 级别是InfoLevel,json格式输出,使用的是NewProductionConfig

func (log Logger) Core() zapcore.Core 回日志程序的底层zapcore.Core
func (log
Logger) Debug(msg string, fields …Field)
func (log Logger) Info(msg string, fields …Field)
func (log
Logger) Warn(msg string, fields …Field)
func (log Logger) Error(msg string, fields …Field)
func (log
Logger) DPanic(msg string, fields …Field)
func (log Logger) Panic(msg string, fields …Field)
func (log
Logger) Fatal(msg string, fields …Field)
func (log Logger) Sugar() SugaredLogger
func (log Logger) Sync() error 调用底层核心的Sync方法,刷新缓冲的日志条目
func (log
Logger) With(fields …Field) Logger 添加字段,不会产生打印效果
func (log
Logger) WithOptions(opts …Option) Logger WithOptions克隆当前日志程序
func (log
Logger) Named(s string) *Logger Named将一个新的路径段添加到记录器的名称中

  1. logger := zap.NewExample()
  2. defer logger.Sync()
  3. // By default, Loggers are unnamed.
  4. logger.Info("no name")
  5. // The first call to Named sets the Logger name.
  6. main := logger.Named("main")
  7. main.Info("main logger")
  8. // Additional calls to Named create a period-separated path.
  9. main.Named("subpackage").Info("sub-logger")
  10. {"level":"info","msg":"no name"}
  11. {"level":"info","logger":"main","msg":"main logger"}
  12. {"level":"info","logger":"main.subpackage","msg":"sub-logger"}

type SugaredLogger

  1. type SugaredLogger struct {
  2. // contains filtered or unexported fields
  3. }

SugaredLogger不坚持结构化日志,使用起来会Logger简单,单性能不如Logger,可以理解位Logger的语法糖

type Option

配置选项

  1. type Option interface {
  2. // contains filtered or unexported methods
  3. }

func AddCaller() Option 记录调用者信息,同WithCaller
func AddCallerSkip(skip int) Option 对AddCaller进行过滤

  1. package main
  2. import (
  3. "go.uber.org/zap"
  4. )
  5. func run(skip int) {
  6. logger, _ := zap.NewDevelopment(zap.AddCaller(), zap.AddCallerSkip(skip))
  7. defer logger.Sync()
  8. logger.Info("hello")
  9. }
  10. func main() {
  11. run(0)
  12. run(1)
  13. run(2)
  14. run(1000) //找不到callercase
  15. }
  16. 2021-12-29T18:10:21.074+0800 INFO afterShip/params_check.go:10 hello
  17. 2021-12-29T18:10:21.075+0800 INFO afterShip/params_check.go:15 hello
  18. 2021-12-29T18:10:21.075+0800 INFO runtime/proc.go:225 hello
  19. 2021-12-29 10:10:21.075128 +0000 UTC Logger.check error: failed to get caller
  20. 2021-12-29T18:10:21.075+0800 INFO hello

func AddStacktrace(lvl zapcore.LevelEnabler) Option 达到指定等级,记录堆栈信息
func Development() Option 开发模式的参数
func ErrorOutput(w zapcore.WriteSyncer) Option 设置日志记录器生成的错误的目标
func Hooks(hooks …func(zapcore.Entry) error) Option 新增勾子
func IncreaseLevel(lvl zapcore.LevelEnabler) Option 增加当前日志等级,如果降低会不起作用
func OnFatal(action zapcore.CheckWriteAction) Option 发生Fatal时需进行的操作
func WithCaller(enabled bool) Option 记录调用者信息
func Fields(fs …Field) Option 设置日志的默认字段

type Field

  1. type Field = zapcore.Field

func Any(key string, value interface{}) Field 一个键,任意值
其它不做介绍,常见的一些类型

type LevelEnablerFunc

LevelEnablerFunc是实现zapcore的一种方便方式。带有匿名函数的LevelEnabler。
当在不同的输出(例如,标准错误和标准输出)之间分割日志输出时,它特别有用。有关示例代码,请参见包级别的AdvancedConfiguration示例。

  1. type LevelEnablerFunc func(zapcore.Level) bool

func (f LevelEnablerFunc) Enabled(lvl zapcore.Level) bool

type Config

  1. type Config struct {
  2. //日志级别,动态的
  3. Level AtomicLevel `json:"level" yaml:"level"`
  4. // 设定为开发模式
  5. Development bool `json:"development" yaml:"development"`
  6. // 禁用调用者信息
  7. DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
  8. // 禁用堆栈跟踪
  9. DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
  10. // 采样策略,nil禁用采样
  11. Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
  12. // 输出格式 console 或 json
  13. Encoding string `json:"encoding" yaml:"encoding"`
  14. // 编码器配置
  15. EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
  16. // 标准输出的指定文件 "stdout"为标准输出
  17. OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
  18. // 标准错误的指定文件 "stderr"为标准错误,注意此设置只影响内部错误;
  19. ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
  20. // 初始化字段,这个字段会被用到每条日志上
  21. InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
  22. }

func NewDevelopmentConfig() Config
func NewProductionConfig() Config
func (cfg Config) Build(opts …Option) (*Logger, error)

type AtomicLevel

可以在运行时,动态的安全的更改日志级别

  1. type AtomicLevel struct {
  2. // contains filtered or unexported fields
  3. }

func NewAtomicLevel() AtomicLevel info级别
func NewAtomicLevelAt(l zapcore.Level) AtomicLevel 指定级别
func (lvl AtomicLevel) Enabled(l zapcore.Level) bool 实现了zapcore.LevelEnabler
func (lvl AtomicLevel) SetLevel(l zapcore.Level) 更改级别
func (lvl AtomicLevel) String() string

type SamplingConfig

SamplingConfig为日志记录器设置一个采样策略。在试图保留日志的一个代表性子集时,采样会限制日志对进程施加的全局CPU和I/O负载。
如果指定,采样器将在每次决策后调用钩子。
这里配置的值为每秒。详情:zapcore.NewSamplerWithOptions

  1. type SamplingConfig struct {
  2. Initial int `json:"initial" yaml:"initial"`
  3. Thereafter int `json:"thereafter" yaml:"thereafter"`
  4. Hook func(zapcore.Entry, zapcore.SamplingDecision) `json:"-" yaml:"-"`
  5. }

例子:

Development

  1. import (
  2. "go.uber.org/zap"
  3. "time"
  4. )
  5. func main() {
  6. logger, _ := zap.NewDevelopment()
  7. defer logger.Sync()
  8. logger.Info("无法获取网址",
  9. zap.String("url", "http://www.baidu.com"),
  10. zap.Int("attempt", 3),
  11. zap.Duration("backoff", time.Second),
  12. )
  13. }

image.png

Production

  1. import (
  2. "go.uber.org/zap"
  3. "time"
  4. )
  5. func main() {
  6. // zap.NewProduction json序列化输出
  7. logger, _ := zap.NewProduction()
  8. defer logger.Sync()
  9. logger.Info("无法获取网址",
  10. zap.String("url", "http://www.baidu.com"),
  11. zap.Int("attempt", 3),
  12. zap.Duration("backoff", time.Second),
  13. )
  14. }

image.png

自定义

选择一个日志库除了高性能是考量的一个标准,高扩展也非常重要,例如:json key 自定义、时间格式化、日志级别等

  1. package main
  2. import (
  3. "go.uber.org/zap"
  4. "go.uber.org/zap/zapcore"
  5. "fmt"
  6. "time"
  7. )
  8. func main() {
  9. encoderConfig := zapcore.EncoderConfig{
  10. TimeKey: "time",
  11. LevelKey: "level",
  12. NameKey: "logger",
  13. CallerKey: "caller",
  14. MessageKey: "msg",
  15. StacktraceKey: "stacktrace",
  16. LineEnding: zapcore.DefaultLineEnding,
  17. EncodeLevel: zapcore.LowercaseLevelEncoder, // 小写编码器
  18. EncodeTime: zapcore.ISO8601TimeEncoder, // ISO8601 UTC 时间格式
  19. EncodeDuration: zapcore.SecondsDurationEncoder,
  20. EncodeCaller: zapcore.FullCallerEncoder, // 全路径编码器
  21. }
  22. // 设置日志级别
  23. atom := zap.NewAtomicLevelAt(zap.DebugLevel)
  24. config := zap.Config{
  25. Level: atom, // 日志级别
  26. Development: true, // 开发模式,堆栈跟踪
  27. Encoding: "json", // 输出格式 console 或 json
  28. EncoderConfig: encoderConfig, // 编码器配置
  29. InitialFields: map[string]interface{}{"serviceName": "spikeProxy"}, // 初始化字段,如:添加一个服务器名称
  30. OutputPaths: []string{"stdout"},
  31. }
  32. // 构建日志
  33. logger, err := config.Build()
  34. if err != nil {
  35. panic(fmt.Sprintf("log 初始化失败: %v", err))
  36. }
  37. logger.Info("log 初始化成功")
  38. logger.Info("无法获取网址",
  39. zap.String("url", "http://www.baidu.com"),
  40. zap.Int("attempt", 3),
  41. zap.Duration("backoff", time.Second),
  42. )
  43. }

image.png