golang集成Context与Zap日志框架的灵活日志记录插件zax的使用
Golang集成Context与Zap日志框架的灵活日志记录插件zax的使用
Zax (zap with context)
Zax是一个为Zap Logger添加上下文支持的库,它让Gopher们能够避免生成logger样板代码。通过将logger作为参数传递给函数,它增强了参数功能,避免了需要多个具有显式依赖关系的方法。
安装
go get -u github.com/yuseferi/zax/v2
使用方法
添加上下文字段
要向上下文添加内容并携带它,只需使用zap.Set:
ctx = zax.Set(ctx, []zap.Field{zap.String("trace_id", "my-trace-id")})
获取上下文中的字段
要检索存储在上下文中的zap字段,使用zax.Get:
zax.Get(ctx) // 这会检索存储在上下文中的zap字段
记录带上下文的日志
要检索存储在上下文中的zap字段并记录它们:
logger.With(zax.Get(ctx)...).Info("just a test record")
获取特定字段
要检索上下文中的特定字段,可以使用zax.GetField:
zax.GetField(ctx, "trace_id")
之后,你可以像使用常规logger一样使用输出并执行日志记录操作:
logger.With(zax.Get(ctx)...).Info("message")
logger.With(zax.Get(ctx)...).Debug("message")
完整示例
假设你想在系统入口点生成一个追踪器,并保持它直到进程完成:
func main() {
logger, _ := zap.NewProduction()
ctx := context.Background()
s := NewServiceA(logger)
ctx = zax.Set(ctx, zap.String("trace_id", "my-trace-id"))
// 如果你想一次添加多个字段
//ctx = zax.Set(ctx, []zap.Field{zap.String("trace_id", "my-trace-id"),zap.String("span_id", "my-span-id")})
s.funcA(ctx)
}
type ServiceA struct {
logger *zap.Logger
}
func NewServiceA(logger *zap.Logger) *ServiceA {
return &ServiceA{
logger: logger,
}
}
func (s *ServiceA) funcA(ctx context.Context) {
s.logger.Info("func A") // 它不包含trace_id,你需要手动添加
s.logger.With(zax.Get(ctx)...).Info("func A") // 它将记录"trace_id" = "my-trace-id"
}
性能基准
我们对Zax V2、V1和Zap使用相同字段进行了基准测试。以下是基准测试结果: 如你所见,V2(在上下文中仅存储字段的方法)比V1(在上下文中存储整个logger对象)具有更好的性能。
pkg: github.com/yuseferi/zax/v2
BenchmarkLoggingWithOnlyZap-10 103801226 35.56 ns/op 112 B/op 1 allocs/op
BenchmarkLoggingWithOnlyZap-10 98576570 35.56 ns/op 112 B/op 1 allocs/op
BenchmarkLoggingWithOnlyZap-10 100000000 35.24 ns/op 112 B/op 1 allocs/op
BenchmarkLoggingWithOnlyZap-10 100000000 34.85 ns/op 112 B/op 1 allocs/op
BenchmarkLoggingWithOnlyZap-10 100000000 34.98 ns/op 112 B/op 1 allocs/op
BenchmarkLoggingWithZaxV2-10 64324434 56.02 ns/op 72 B/op 2 allocs/op
BenchmarkLoggingWithZaxV2-10 63939517 56.98 ns/op 72 B/op 2 allocs/op
BenchmarkLoggingWithZaxV2-10 63374052 57.60 ns/op 72 B/op 2 allocs/op
BenchmarkLoggingWithZaxV2-10 63417358 57.37 ns/op 72 B/op 2 allocs/op
BenchmarkLoggingWithZaxV2-10 57964246 57.97 ns/op 72 B/op 2 allocs/op
BenchmarkLoggingWithZaxV1-10 54062712 66.40 ns/op 160 B/op 2 allocs/op
BenchmarkLoggingWithZaxV1-10 53155524 65.61 ns/op 160 B/op 2 allocs/op
BenchmarkLoggingWithZaxV1-10 54428521 64.19 ns/op 160 B/op 2 allocs/op
BenchmarkLoggingWithZaxV1-10 55420744 64.28 ns/op 160 B/op 2 allocs/op
BenchmarkLoggingWithZaxV1-10 55199061 64.50 ns/op 160 B/op 2 allocs/op
PASS
ok github.com/yuseferi/zax/v2 56.919s
贡献
我们坚信开源精神❤️😊。请随时通过提出问题并提交拉取请求来贡献,使Zax变得更好!
更多关于golang集成Context与Zap日志框架的灵活日志记录插件zax的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang集成Context与Zap日志框架的灵活日志记录插件zax的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang集成Context与Zap日志框架的zax插件使用指南
什么是zax
zax是一个基于Zap日志框架的插件,它提供了与Context集成的能力,使得日志记录更加灵活和上下文感知。zax的主要特点包括:
- 与标准库
context.Context
无缝集成 - 支持结构化日志记录
- 高性能,基于Zap的高效日志记录能力
- 支持日志字段的链式调用
安装zax
go get github.com/uber-go/zap
go get github.com/yourusername/zax
基本使用示例
package main
import (
"context"
"time"
"go.uber.org/zap"
"github.com/yourusername/zax"
)
func main() {
// 创建基础logger
logger, _ := zap.NewProduction()
defer logger.Sync() // 确保日志被刷新
// 创建zax logger
zaxLogger := zax.New(logger)
// 创建context
ctx := context.Background()
// 为context添加日志字段
ctx = zax.WithFields(ctx, zap.String("request_id", "12345"), zap.String("user", "john"))
// 记录日志
zaxLogger.Info(ctx, "User logged in", zap.Duration("duration", 100*time.Millisecond))
}
高级功能
1. 上下文字段继承
func handleRequest(ctx context.Context, zaxLogger *zax.Logger) {
// 添加更多上下文字段
ctx = zax.WithFields(ctx, zap.String("handler", "user_profile"))
// 所有日志都会自动包含request_id, user和handler字段
zaxLogger.Info(ctx, "Processing request")
}
2. 动态字段添加
func processOrder(ctx context.Context, zaxLogger *zax.Logger, orderID string) {
// 动态添加字段
zaxLogger.With(zap.String("order_id", orderID)).Info(ctx, "Order processed")
}
3. 错误处理
func someOperation(ctx context.Context, zaxLogger *zax.Logger) error {
err := doSomething()
if err != nil {
zaxLogger.Error(ctx, "Operation failed", zap.Error(err))
return err
}
return nil
}
性能优化建议
- 复用Logger实例:避免在每次请求时创建新的Logger实例
- 预分配字段:对于高频日志,预先分配字段可以减少内存分配
- 使用zap的采样配置:在高负载环境下启用采样
func setupLogger() *zax.Logger {
config := zap.NewProductionConfig()
config.Sampling = &zap.SamplingConfig{
Initial: 100,
Thereafter: 100,
}
logger, _ := config.Build()
return zax.New(logger)
}
自定义配置示例
func customLogger() *zax.Logger {
// 自定义encoder配置
encoderCfg := zapcore.EncoderConfig{
TimeKey: "timestamp",
LevelKey: "level",
NameKey: "logger",
CallerKey: "caller",
FunctionKey: zapcore.OmitKey,
MessageKey: "message",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.LowercaseLevelEncoder,
EncodeTime: zapcore.ISO8601TimeEncoder,
EncodeDuration: zapcore.StringDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
// 创建自定义core
core := zapcore.NewCore(
zapcore.NewJSONEncoder(encoderCfg),
zapcore.AddSync(os.Stdout),
zap.InfoLevel,
)
// 创建logger
logger := zap.New(core)
return zax.New(logger)
}
最佳实践
-
合理使用日志级别:
- Debug: 开发调试信息
- Info: 重要业务事件
- Warn: 需要注意但不影响流程的问题
- Error: 需要立即调查的错误
-
结构化日志:始终使用结构化字段而非字符串拼接
-
敏感信息过滤:不要在日志中记录密码、token等敏感信息
-
上下文传递:通过context传递请求级别的日志字段
zax通过将Zap的强大功能与Context的灵活性结合,为Golang应用提供了高效且易于使用的日志解决方案。