Gin日志记录与性能监控中间件
日志和监控是运维的基础,完善的中间件实现可快速定位问题和优化性能。
Gin内置Logger中间件
默认Logger实现
Go
func Logger() HandlerFunc {
return LoggerWithConfig(LoggerConfig{})
}
type LoggerConfig struct {
SkipPaths []string
Output io.Writer
Formatter LogFormatter
}
func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
formatter := conf.Formatter
if formatter == nil {
formatter = defaultFormatter
}
return func(c *Context) {
path := c.Request.URL.Path
start := time.Now()
c.Next()
// 跳过指定路径
if inSliceString(path, conf.SkipPaths) {
return
}
param := LogFormatterParams{
Request: c.Request,
TimeStamp: time.Now(),
StatusCode: c.Writer.Status(),
Latency: time.Since(start),
ClientIP: c.ClientIP(),
Method: c.Request.Method,
Path: path,
}
formatter(param)
}
}
自定义日志中间件
结构化日志
Go
func StructuredLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
method := c.Request.Method
// 请求信息
log.Printf("[Request] method=%s path=%s ip=%s",
method, path, c.ClientIP())
c.Next()
// 响应信息
duration := time.Since(start)
status := c.Writer.Status()
log.Printf("[Response] method=%s path=%s status=%d duration=%v size=%d",
method, path, status, duration, c.Writer.Size())
}
}
JSON格式日志
Go
func JSONLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
entry := map[string]any{
"timestamp": time.Now().Format(time.RFC3339),
"method": c.Request.Method,
"path": c.Request.URL.Path,
"status": c.Writer.Status(),
"duration": time.Since(start).Milliseconds(),
"client_ip": c.ClientIP(),
"size": c.Writer.Size(),
"trace_id": c.GetString("traceID"),
}
jsonEntry, _ := json.Marshal(entry)
fmt.Println(string(jsonEntry))
}
}
性能监控中间件
响应时间监控
Go
func PerformanceMonitor() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
c.Next()
duration := time.Since(start)
// 超时告警
if duration > 1*time.Second {
log.Printf("[WARN] Slow request: path=%s duration=%v", path, duration)
}
// 记录指标
metrics.RecordLatency(path, duration)
}
}
Prometheus指标集成
Go
var (
httpRequestsTotal = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
[]string{"method", "path", "status"},
)
httpRequestDuration = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds",
Buckets: []float64{.01, .05, .1, .5, 1, 5},
},
[]string{"method", "path"},
)
)
func PrometheusMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
method := c.Request.Method
c.Next()
status := c.Writer.Status()
duration := time.Since(start).Seconds()
httpRequestsTotal.WithLabelValues(method, path, fmt.Sprintf("%d", status)).Inc()
httpRequestDuration.WithLabelValues(method, path).Observe(duration)
}
}
请求追踪中间件
TraceID生成与传递
Go
func TraceMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 从请求头获取或生成TraceID
traceID := c.GetHeader("X-Trace-ID")
if traceID == "" {
traceID = uuid.New().String()
}
// 存储到Context
c.Set("traceID", traceID)
// 设置响应头
c.Header("X-Trace-ID", traceID)
c.Next()
}
}
增强日志记录
Go
func TracedLogger() gin.HandlerFunc {
return func(c *gin.Context) {
traceID := c.GetString("traceID")
start := time.Now()
log.Printf("[%s] >>> %s %s", traceID, c.Request.Method, c.Request.URL.Path)
c.Next()
log.Printf("[%s] <<< %d %v", traceID, c.Writer.Status(), time.Since(start))
}
}
日志中间件配置
跳过健康检查路径
Go
r := gin.New()
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{
SkipPaths: []string{
"/health",
"/metrics",
"/favicon.ico",
},
}))
自定义日志格式
Go
func customFormatter(param gin.LogFormatterParams) string {
return fmt.Sprintf("[GIN] %v | %3d | %13v | %15s | %-7s %#v\n",
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
param.StatusCode,
param.Latency,
param.ClientIP,
param.Method,
param.Path,
)
}
r.Use(gin.LoggerWithFormatter(customFormatter))
监控指标汇总
| 指标类型 | Prometheus类型 | 说明 |
|---|---|---|
| 请求数量 | Counter | 各路径请求总数 |
| 响应时间 | Histogram | 请求耗时分布 |
| 并发数 | Gauge | 当前并发请求 |
| 错误率 | Counter | 各状态码数量 |
注意:健康检查路径应跳过日志记录,避免日志量过大。
要点总结
- Logger默认记录请求时间、状态码、耗时、路径
- 使用LoggerConfig跳过特定路径日志
- 结构化日志便于日志系统解析
- Prometheus中间件记录请求指标
- TraceID串联请求链路,便于追踪分析
📝 发现内容有误?点击此处直接编辑