第24章:日志系统
本章目标
学完本章后,你将能够:
- 自定义 Gin 日志格式(带 TraceID)
- 将日志写入文件
- 集成 Zap 高性能日志库
- 实现请求追踪(TraceID 传递)
前置知识
- 需要先学习:第15-16章(内置中间件、自定义中间件)
24.1 自定义 Gin 日志格式
go
r := gin.New()
r.Use(gin.LoggerWithFormatter(func(params gin.LogFormatterParams) string {
return fmt.Sprintf("[%s] %s | %d | %v | %s | %s %s\n",
params.TimeStamp.Format("2006-01-02 15:04:05"),
params.ClientIP,
params.StatusCode,
params.Latency,
params.Method,
params.Path,
params.ErrorMessage,
)
}))24.2 日志写入文件
go
// 打开日志文件
f, _ := os.Create("gin.log")
// 同时输出到文件和控制台
gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
r := gin.Default()
// 现在日志同时写入 gin.log 文件和控制台24.3 集成 Zap(生产推荐)
go
import "go.uber.org/zap"
func main() {
logger, _ := zap.NewProduction()
defer logger.Sync()
r := gin.New()
// 用 Zap 记录 Gin 请求日志
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{
Formatter: func(params gin.LogFormatterParams) string {
logger.Info("HTTP请求",
zap.String("method", params.Method),
zap.String("path", params.Path),
zap.Int("status", params.StatusCode),
zap.Duration("latency", params.Latency),
zap.String("ip", params.ClientIP),
)
return "" // Gin 的 Logger 需要返回值,但 Zap 已处理
},
}))
r.Run(":8080")
}24.4 完整示例:TraceID + 结构化日志
go
package main
import (
"fmt"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
func main() {
r := gin.New()
// TraceID 中间件
r.Use(func(c *gin.Context) {
traceID := c.GetHeader("X-Trace-ID")
if traceID == "" {
traceID = uuid.New().String()
}
c.Set("trace_id", traceID)
c.Header("X-Trace-ID", traceID)
c.Next()
})
// 日志中间件(带 TraceID)
r.Use(func(c *gin.Context) {
start := time.Now()
c.Next()
traceID, _ := c.Get("trace_id")
fmt.Printf("[%s] %s | %d | %v | %s %s\n",
traceID,
c.ClientIP(),
c.Writer.Status(),
time.Since(start),
c.Request.Method,
c.Request.URL.Path,
)
})
r.GET("/hello", func(c *gin.Context) {
c.String(200, "hello")
})
r.Run(":8080")
}本章小结
LoggerWithFormatter自定义日志格式gin.DefaultWriter = io.MultiWriter(file, stdout)写文件- 生产环境推荐 Zap/Logrus + 结构化日志
- TraceID 贯穿请求全链路
练习题
- 自定义 Gin 日志格式,包含客户端 IP、方法、路径、状态码、耗时。
- 将 Gin 日志同时输出到文件和控制台。
- 集成 Zap 日志库,用结构化日志记录请求。
- (思考题)为什么生产环境需要结构化日志(而非纯文本)?