golang 日志库:uber-go/zap

发布时间: 更新时间: 总字数:913 阅读时间:2m 作者: IP上海 分享 网址

uber-go/zap 是 Go 中的快速、结构化、分级日志记录方案。

介绍

  • 性能优异,比标准库更快,相关数据参考
  • 支持结构化日志记录和 printf 风格的日志
  • Zap 提供了两种类型的日志记录器
    • Sugared Logger 要求性能很好但不是很关键的上下文中使用,比其他结构化日志记录包快 4-10 倍,支持结构化日志记录和 printf 风格的日志
    • Logger 在每一微秒和每一次内存分配都很重要的上下文中,只支持强类型的结构化日志记录

使用

基本使用

示例一:


示例二:


输出:

{"level":"error","ts":1734856179.3081212,"caller":"zap/demo1.go:20","msg":"Error fetching url..","url":"www.xiexianbin.cn","error":"Get \"www.xiexianbin.cn\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/xiexianbin/workspace/code/github.com/xiexianbin/note/static/code/golang/zap/demo1.go:20\nmain.main\n\t/Users/xiexianbin/workspace/code/github.com/xiexianbin/note/static/code/golang/zap/demo1.go:39\nruntime.main\n\t/usr/local/Cellar/go/1.23.2/libexec/src/runtime/proc.go:272"}
{"level":"error","ts":1734856179.308209,"caller":"zap/demo1.go:25","msg":"Error fetching url..","type":"sugar","url":"www.xiexianbin.cn","error":"Get \"www.xiexianbin.cn\": unsupported protocol scheme \"\"","stacktrace":"main.simpleHttpGet\n\t/Users/xiexianbin/workspace/code/github.com/xiexianbin/note/static/code/golang/zap/demo1.go:25\nmain.main\n\t/Users/xiexianbin/workspace/code/github.com/xiexianbin/note/static/code/golang/zap/demo1.go:39\nruntime.main\n\t/usr/local/Cellar/go/1.23.2/libexec/src/runtime/proc.go:272"}
{"level":"info","ts":1734856179.342197,"caller":"zap/demo1.go:27","msg":"Success..","statusCode":"200 OK","url":"https://www.xiexianbin.cn"}
{"level":"info","ts":1734856179.3422499,"caller":"zap/demo1.go:31","msg":"Success..","type":"sugar","statusCode":"200 OK","url":"https://www.xiexianbin.cn"}

定制日志级别、输出文件、打印代码的位置和格式


输出:

$ cat test.log
2024-12-22T16:33:12.346+0800    ERROR   zap/demo2.go:38 Error fetching url..    {"url": "www.xiexianbin.cn", "error": "Get \"www.xiexianbin.cn\": unsupported protocol scheme \"\""}
2024-12-22T16:33:12.381+0800    INFO    zap/demo2.go:43 Success..       {"statusCode": "200 OK", "url": "https://www.xiexianbin.cn"}
$ cat test.err.log
2024-12-22T16:33:12.346+0800    ERROR   zap/demo2.go:38 Error fetching url..    {"url": "www.xiexianbin.cn", "error": "Get \"www.xiexianbin.cn\": unsupported protocol scheme \"\""}

说明:

  • 封装 zap 日志后,可以使用 zap.AddCallerSkip(1) 获取准确的代码位置

Lumberjack 分割日志文件


配置

zap.NewExample()

  • 构建一个测试使用的 Logger,DebugLevel 及以上日志,JSON 格式
// https://github.com/uber-go/zap/blob/v1.27.0/logger.go#L125C1-L141C1
// NewExample builds a Logger that's designed for use in zap's testable
// examples. It writes DebugLevel and above logs to standard out as JSON, but
// omits the timestamp and calling function to keep example output
// short and deterministic.
func NewExample(options ...Option) *Logger {
	encoderCfg := zapcore.EncoderConfig{
		MessageKey:     "msg",
		LevelKey:       "level",
		NameKey:        "logger",
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.StringDurationEncoder,
	}
	core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel)
	return New(core).WithOptions(options...)
}

zap.NewDevelopment()

  • 构建一个开发使用的 Logger,DebugLevel 及以上人性化的格式
// https://github.com/uber-go/zap/blob/v1.27.0/logger.go#L104C1-L110C2
// NewDevelopment builds a development Logger that writes DebugLevel and above
// logs to standard error in a human-friendly format.
//
// It's a shortcut for NewDevelopmentConfig().Build(...Option).
func NewDevelopment(options ...Option) (*Logger, error) {
	return NewDevelopmentConfig().Build(options...)
}

zap.NewProduction()

  • 构建一个开发使用的生产使用呢的 Logger,InfoLevel 及以上日志,JSON 格式
// https://github.com/uber-go/zap/blob/v1.27.0/logger.go#L96C1-L102C2
// NewProduction builds a sensible production Logger that writes InfoLevel and
// above logs to standard error as JSON.
//
// It's a shortcut for NewProductionConfig().Build(...Option).
func NewProduction(options ...Option) (*Logger, error) {
	return NewProductionConfig().Build(options...)
}

配置 Option 示例

	logger, _ := zap.NewProduction(zap.Fields(
		zap.String("log_name", "testlog"),
		zap.String("log_author", "prometheus"),
	))
	defer logger.Sync()

配置 Hook 示例

	logger := zap.NewExample(zap.Hooks(func(entry zapcore.Entry) error {
		fmt.Println("zap test Hooks")
		return nil
	}))
	defer logger.Sync()
  • namespace 示例
package main

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

func main() {
	logger := zap.NewExample()
	defer logger.Sync()

	logger.Info("some message",
		zap.Namespace("shop"),
		zap.String("name", "LiLei"),
		zap.String("grade", "No2"),
	)

	logger.Error("some error message",
		zap.Namespace("shop"),
		zap.String("name", "LiLei"),
		zap.String("grade", "No3"),
	)
}

全局 Logger

package main

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

func main() {
	// 直接调用是不会记录日志信息的,下面日志信息不会输出
	zap.L().Info("no log info")
	zap.S().Info("no log info [sugared]")

	// 初始化日志
	logger := zap.NewExample()
	defer logger.Sync()

	// 全局logger,zap.L() 和 zap.S() 需要调用 ReplaceGlobals 函数才会记录日志信息
	zap.ReplaceGlobals(logger)
	zap.L().Info("log info")
	zap.S().Info("log info [sugared]")
}

重定向标准日志库 log

package main

import (
	"log"

	"go.uber.org/zap"
)

func main() {
	logger := zap.NewExample()
	defer logger.Sync()

	// RedirectStdLogAt 可以添加日志级别
	undo := zap.RedirectStdLog(logger)
	log.Print("redirected standard library")
	undo()

	log.Print("this zap logger")
}

输出调用堆栈

package main

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

func Hello() {
	Warn("hello", zap.String("h", "world"), zap.Int("c", 1))
}

func Warn(msg string, fields ...zap.Field) {
	zap.L().Warn(msg, fields...)
}

func main() {
	logger, _ := zap.NewProduction(zap.AddStacktrace(zapcore.WarnLevel))
	defer logger.Sync()

	zap.ReplaceGlobals(logger)

	Hello()
}

输出文件名和行号

package main

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

func main() {
	logger, _ := zap.NewProduction(zap.AddCaller())
	defer logger.Sync()

	logger.Info("AddCaller:line No and filename")
}
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数