Skip to content

第24章:日志系统 ​

本章目标 ​

学完本章后,你将能够:

  1. 自定义 Gin 日志格式(带 TraceID)
  2. 将日志写入文件
  3. 集成 Zap 高性能日志库
  4. 实现请求追踪(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 贯穿请求全链路

练习题 ​

  1. 自定义 Gin 日志格式,包含客户端 IP、方法、路径、状态码、耗时。
  2. 将 Gin 日志同时输出到文件和控制台。
  3. 集成 Zap 日志库,用结构化日志记录请求。
  4. (思考题)为什么生产环境需要结构化日志(而非纯文本)?

把零散知识,整理成可以反复走的路。