# 🚀 Zap 官方最佳实践日志系统指南 ## 概述 本日志系统完全基于 [Zap 官方最佳实践](https://betterstack.com/community/guides/logging/go/zap/) 设计,使用 `zap.NewProduction()` 和 `zap.NewDevelopment()` 预设,提供高性能、结构化的日志记录。 ## ✨ 核心特性 ### 1. **基于 Zap 官方预设** - 使用 `zap.NewProduction()` 生产环境预设 - 使用 `zap.NewDevelopment()` 开发环境预设 - 自动添加调用者信息、堆栈跟踪等 ### 2. **全局日志器支持** - 支持 `zap.ReplaceGlobals()` 全局替换 - 提供 `logger.L()` 和 `logger.GetGlobalLogger()` 访问 - 符合 Zap 官方推荐的使用方式 ### 3. **强类型字段支持** - 使用 `zap.String()`, `zap.Int()`, `zap.Error()` 等强类型字段 - 避免运行时类型错误 - 提供最佳性能 ### 4. **上下文日志记录** - 自动从上下文提取 `request_id`, `user_id`, `trace_id` - 支持 `WithContext()` 方法 - 便于分布式系统追踪 ## 🏗️ 架构设计 ### 核心接口 ```go type Logger interface { // 基础日志方法 Debug(msg string, fields ...zapcore.Field) Info(msg string, fields ...zapcore.Field) Warn(msg string, fields ...zapcore.Field) Error(msg string, fields ...zapcore.Field) Fatal(msg string, fields ...zapcore.Field) Panic(msg string, fields ...zapcore.Field) // 结构化日志方法 With(fields ...zapcore.Field) Logger WithContext(ctx context.Context) Logger Named(name string) Logger // 同步和清理 Sync() error Core() zapcore.Core // 获取原生 Zap Logger GetZapLogger() *zap.Logger } ``` ### 实现类型 1. **ZapLogger**: 标准日志器,基于 Zap 官方预设 2. **LevelLogger**: 级别分文件日志器,支持按级别分离 3. **全局日志器**: 通过 `zap.ReplaceGlobals()` 提供全局访问 ## 🚀 使用方法 ### 1. 基础使用 ```go package main import ( "go.uber.org/zap" "tyapi-server/internal/shared/logger" ) func main() { // 初始化全局日志器 config := logger.Config{ Development: true, Output: "stdout", Format: "console", } if err := logger.InitGlobalLogger(config); err != nil { panic(err) } // 使用全局日志器 logger.L().Info("应用启动成功") // 或者获取全局日志器 globalLogger := logger.GetGlobalLogger() globalLogger.Info("使用全局日志器") } ``` ### 2. 依赖注入使用 ```go type ProductService struct { logger logger.Logger } func NewProductService(logger logger.Logger) *ProductService { return &ProductService{logger: logger} } func (s *ProductService) CreateProduct(ctx context.Context, product *Product) error { // 记录操作日志 s.logger.Info("创建产品", zap.String("product_id", product.ID), zap.String("product_name", product.Name), zap.String("user_id", product.CreatedBy), ) // 业务逻辑... return nil } ``` ### 3. 上下文日志记录 ```go func (s *ProductService) GetProduct(ctx context.Context, id string) (*Product, error) { // 自动从上下文提取字段 logger := s.logger.WithContext(ctx) logger.Info("获取产品信息", zap.String("product_id", id), zap.String("operation", "get_product"), ) // 业务逻辑... return product, nil } ``` ### 4. 结构化字段 ```go // 使用强类型字段 s.logger.Info("用户登录", zap.String("username", "john_doe"), zap.Int("user_id", 12345), zap.String("ip_address", "192.168.1.100"), zap.String("user_agent", r.UserAgent()), zap.Time("login_time", time.Now()), ) // 记录错误 if err != nil { s.logger.Error("数据库操作失败", zap.Error(err), zap.String("operation", "create_user"), zap.String("table", "users"), ) } ``` ### 5. 级别分文件日志 ```go // 配置启用级别分文件 config := logger.Config{ EnableLevelSeparation: true, Output: "file", LogDir: "logs", UseDaily: true, LevelConfigs: map[string]interface{}{ "debug": map[string]interface{}{ "max_size": 50, "max_backups": 3, "max_age": 7, }, "error": map[string]interface{}{ "max_size": 200, "max_backups": 10, "max_age": 90, }, }, } // 创建级别分文件日志器 levelLogger, err := logger.NewLevelLogger(logger.LevelLoggerConfig{ BaseConfig: config, EnableLevelSeparation: true, LevelConfigs: convertLevelConfigs(config.LevelConfigs), }) ``` ## 📁 日志文件结构 ### 按级别分文件 ``` logs/ ├── 2024-01-01/ │ ├── debug.log # 调试日志 │ ├── info.log # 信息日志 │ ├── warn.log # 警告日志 │ ├── error.log # 错误日志 │ ├── fatal.log # 致命错误日志 │ └── panic.log # 恐慌错误日志 └── app.log # 主日志文件 ``` ### 按日期分包 ``` logs/ ├── 2024-01-01/ │ ├── app.log │ └── error.log ├── 2024-01-02/ │ ├── app.log │ └── error.log └── app.log # 当前日期 ``` ## ⚙️ 配置选项 ### 基础配置 ```yaml logger: # 环境配置 development: true # 是否为开发环境 # 输出配置 output: "file" # 输出方式: stdout, stderr, file format: "json" # 输出格式: json, console log_dir: "logs" # 日志目录 # 文件配置 max_size: 100 # 单个文件最大大小(MB) max_backups: 5 # 最大备份文件数 max_age: 30 # 最大保留天数 compress: true # 是否压缩 # 高级功能 use_daily: true # 是否按日分包 enable_level_separation: true # 是否启用按级别分文件 use_color: false # 是否使用彩色输出 ``` ### 级别配置 ```yaml logger: level_configs: debug: max_size: 50 # 50MB max_backups: 3 # 3个备份 max_age: 7 # 7天 compress: true info: max_size: 100 # 100MB max_backups: 5 # 5个备份 max_age: 30 # 30天 compress: true error: max_size: 200 # 200MB max_backups: 10 # 10个备份 max_age: 90 # 90天 compress: true ``` ## 🔧 最佳实践 ### 1. **使用强类型字段** ```go // ✅ 推荐:使用强类型字段 logger.Info("用户操作", zap.String("user_id", userID), zap.String("action", "login"), zap.Time("timestamp", time.Now()), ) // ❌ 避免:使用 Any 字段 logger.Info("用户操作", zap.Any("user_id", userID), zap.Any("action", "login"), zap.Any("timestamp", time.Now()), ) ``` ### 2. **合理使用日志级别** ```go // Debug: 详细的调试信息 logger.Debug("SQL查询", zap.String("query", sql)) // Info: 重要的业务事件 logger.Info("用户注册成功", zap.String("user_id", userID)) // Warn: 警告信息,不影响功能 logger.Warn("数据库连接池使用率过高", zap.Int("usage", 85)) // Error: 错误信息,功能受影响 logger.Error("数据库连接失败", zap.Error(err)) // Fatal: 致命错误,应用无法继续 logger.Fatal("配置文件加载失败", zap.Error(err)) ``` ### 3. **上下文信息提取** ```go // 在中间件中设置上下文 func LoggingMiddleware(logger logger.Logger) gin.HandlerFunc { return func(c *gin.Context) { // 生成请求ID requestID := uuid.New().String() // 设置上下文 ctx := context.WithValue(c.Request.Context(), "request_id", requestID) ctx = context.WithValue(ctx, "user_id", getUserID(c)) ctx = context.WithValue(ctx, "trace_id", getTraceID(c)) c.Request = c.Request.WithContext(ctx) // 记录请求日志 logger.WithContext(ctx).Info("收到请求", zap.String("method", c.Request.Method), zap.String("path", c.Request.URL.Path), zap.String("client_ip", c.ClientIP()), ) c.Next() } } ``` ### 4. **性能优化** ```go // ✅ 推荐:延迟计算 if logger.Core().Enabled(zapcore.DebugLevel) { logger.Debug("调试信息", zap.String("data", expensiveOperation())) } // ❌ 避免:总是计算 logger.Debug("调试信息", zap.String("data", expensiveOperation())) ``` ## 🚨 错误处理 ### 1. **Panic 恢复** ```go // 使用 panic 恢复中间件 func PanicRecoveryMiddleware(logger *zap.Logger) gin.HandlerFunc { return gin.RecoveryWithWriter(&panicLogger{logger: logger}) } type panicLogger struct { logger *zap.Logger } func (pl *panicLogger) Write(p []byte) (n int, err error) { pl.logger.Error("系统发生严重错误", zap.String("error_type", "panic"), zap.String("stack_trace", string(p)), zap.String("timestamp", time.Now().Format("2006-01-02 15:04:05")), ) return len(p), nil } ``` ### 2. **错误日志记录** ```go // 记录错误详情 if err != nil { logger.Error("操作失败", zap.Error(err), zap.String("operation", "create_user"), zap.String("user_id", userID), zap.String("stack_trace", string(debug.Stack())), ) return err } ``` ## 📊 性能基准 基于 [Zap 官方基准测试](https://betterstack.com/community/guides/logging/go/zap/): | 包 | 时间 | 相对于 Zap | 内存分配 | |----|------|------------|----------| | zap | 193 ns/op | +0% | 0 allocs/op | | zap (sugared) | 227 ns/op | +18% | 1 allocs/op | | zerolog | 81 ns/op | -58% | 0 allocs/op | | slog | 322 ns/op | +67% | 0 allocs/op | ## 🔍 调试和故障排除 ### 1. **检查日志级别** ```go // 检查日志级别是否启用 if logger.Core().Enabled(zapcore.DebugLevel) { logger.Debug("调试信息") } ``` ### 2. **同步日志** ```go // 确保日志写入完成 defer logger.Sync() // 或者在应用关闭时 func cleanup() { logger.Sync() } ``` ### 3. **验证配置** ```go // 验证日志器配置 config := logger.Config{ Development: true, Output: "stdout", Format: "console", } logger, err := logger.NewLogger(config) if err != nil { log.Fatalf("创建日志器失败: %v", err) } ``` ## 🎯 总结 本日志系统完全基于 Zap 官方最佳实践设计,具有以下优势: 1. **高性能**: 基于 Zap 的高性能实现 2. **官方推荐**: 使用 `zap.NewProduction()` 和 `zap.NewDevelopment()` 预设 3. **强类型**: 支持强类型字段,避免运行时错误 4. **结构化**: 支持结构化日志记录 5. **上下文**: 自动提取上下文信息 6. **灵活配置**: 支持文件输出、级别分离、按日分包等 7. **全局访问**: 支持全局日志器访问 通过合理使用,您将获得高性能、结构化的日志系统,满足生产环境的各种需求! ## 📚 参考资源 - [Zap 官方文档](https://pkg.go.dev/go.uber.org/zap) - [Zap 最佳实践指南](https://betterstack.com/community/guides/logging/go/zap/) - [Zap GitHub 仓库](https://github.com/uber-go/zap)