日志管理:从 log 到 zap
日志是排查问题的第一手段。一个好的日志系统应该:结构化、高性能、可配置、易于检索。 1. 标准库 log 1.1 基础使用 package main import ( "log" ) func main() { log.Println("This is a log message") log.Printf("User %s logged in", "admin") // log.Fatal 会调用 os.Exit(1) // log.Fatal("Fatal error") // log.Panic 会触发 panic // log.Panic("Panic error") } 1.2 自定义 Logger import ( "log" "os" ) func main() { // 创建自定义 Logger logger := log.New( os.Stdout, // 输出目标 "[MyApp] ", // 前缀 log.Ldate|log.Ltime|log.Lshortfile, // 标志 ) logger.Println("Custom logger message") // 输出:[MyApp] 2025/12/18 10:00:00 main.go:15: Custom logger message } 1.3 写入文件 func main() { file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) if err != nil { panic(err) } defer file.Close() log.SetOutput(file) log.Println("This goes to file") } 2. slog:结构化日志 (Go 1.21+) 2.1 基础使用 import ( "log/slog" "os" ) func main() { // 创建 JSON 格式的 Logger logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) logger.Info("User logged in", "user_id", 123, "username", "admin", "ip", "192.168.1.1") // 输出: // {"time":"2025-12-18T10:00:00Z","level":"INFO","msg":"User logged in","user_id":123,"username":"admin","ip":"192.168.1.1"} } 2.2 日志级别 func main() { logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelInfo, // 只输出 Info 及以上级别 })) logger.Debug("Debug message") // 不会输出 logger.Info("Info message") // 会输出 logger.Warn("Warning message") // 会输出 logger.Error("Error message") // 会输出 } 2.3 上下文日志 func main() { logger := slog.Default() // 创建带有固定字段的子 Logger requestLogger := logger.With( "request_id", "abc123", "user_id", 456, ) requestLogger.Info("Processing request") requestLogger.Info("Request completed") // 两条日志都会自动包含 request_id 和 user_id } 3. zap:高性能日志库 3.1 安装 go get -u go.uber.org/zap 3.2 快速开始 import ( "go.uber.org/zap" ) func main() { // 开发环境:易读的格式 logger, _ := zap.NewDevelopment() defer logger.Sync() // 刷新缓冲区 logger.Info("User logged in", zap.String("username", "admin"), zap.Int("user_id", 123)) // 生产环境:JSON 格式 prodLogger, _ := zap.NewProduction() defer prodLogger.Sync() prodLogger.Info("Server started", zap.String("port", "8080")) } 3.3 自定义配置 func main() { config := zap.NewProductionConfig() // 设置日志级别 config.Level = zap.NewAtomicLevelAt(zap.InfoLevel) // 设置输出路径 config.OutputPaths = []string{ "stdout", "./logs/app.log", } // 设置错误日志路径 config.ErrorOutputPaths = []string{ "stderr", "./logs/error.log", } logger, _ := config.Build() defer logger.Sync() logger.Info("Application started") } 3.4 性能对比 // zap 提供了 SugaredLogger,牺牲一点性能换取更简洁的 API logger, _ := zap.NewProduction() sugar := logger.Sugar() // 结构化日志(最快) logger.Info("User logged in", zap.String("username", "admin")) // 格式化日志(稍慢,但更方便) sugar.Infof("User %s logged in", "admin") 4. 日志分级 4.1 日志级别 从低到高: ...