Skip to content
Go
链路追踪与可观测性

链路追踪与可观测性

go-zero 从 v1.5.0 起全面基于 OpenTelemetry 实现可观测性,自动为 HTTP、gRPC、SQL、Redis 创建 Span,配合 Prometheus 指标和结构化日志,形成完整的可观测性体系。


可观测性三支柱

┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│   Traces     │   │   Metrics    │   │    Logs      │
│  链路追踪    │   │  指标监控    │   │  结构化日志  │
├──────────────┤   ├──────────────┤   ├──────────────┤
│ OpenTelemetry│   │ Prometheus   │   │ logx (JSON)  │
│ → Jaeger     │   │ → Grafana    │   │ → ELK/Loki   │
└──────────────┘   └──────────────┘   └──────────────┘
       │                  │                  │
       └──────────────────┼──────────────────┘
                 trace_id 关联

链路追踪配置

服务端配置

Telemetry:
  Name: user-api               # 服务名称(在 Jaeger 中显示)
  Endpoint: jaeger:4317        # OTLP gRPC 端点
  Sampler: 1.0                 # 采样率 0.0 ~ 1.0
  Batcher: otlpgrpc            # otlpgrpc | otlphttp

代码加载

// etc/config.go
type Config struct {
    rest.RestConf
    Telemetry trace.Config
}

go-zero 在第一次请求时自动注册追踪器,无需额外代码

采样策略

策略 配置 适用场景
全量采样 Sampler: 1.0 开发/预发布环境
10% 采样 Sampler: 0.1 普通生产环境
1% 采样 Sampler: 0.01 高吞吐(>10k QPS)

💡 采样在 Trace 根节点(API 网关)决策,同一 Trace 的所有下游 Span 自动跟随。


Jaeger 部署(OTLP 协议)

🚨 重要:go-zero v1.10.0 起移除了 jaeger batcher,统一使用 OTLP 协议。Jaeger 版本需 ≥1.35。

Docker Compose 部署

version: "3"
services:
  jaeger:
    image: jaegertracing/all-in-one:1.57
    ports:
      - "16686:16686"   # Web UI
      - "4317:4317"     # OTLP gRPC(go-zero 使用)
      - "4318:4318"     # OTLP HTTP(可选)
    environment:
      - COLLECTOR_OTLP_ENABLED=true

go-zero 配置对应

Telemetry:
  Name: my-service
  Endpoint: localhost:4317     # 对应 OTLP gRPC 端口
  Sampler: 1.0
  Batcher: otlpgrpc

Jaeger UI

访问 http://localhost:16686 查看链路追踪。


自动追踪内容

go-zero 自动为以下组件创建 Span(零代码改动):

组件 追踪内容
HTTP 入站 URL、方法、状态码、耗时
HTTP 出站 目标 URL、方法、状态码
gRPC 调用 服务名、方法名、状态码
SQL 查询(sqlx) SQL 语句、影响行数、耗时
Redis 命令 命令名称、Key 前缀、耗时

跨服务传播

使用 W3C TraceContext 标准,通过 traceparent Header 自动传递 trace_id 和 span_id。

API → RPC:   request header { "traceparent": "00-<traceId>-<spanId>-01" }
RPC → DB:    context 传递 trace_id

自定义业务 Span

import (
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/attribute"
)

func (l *OrderLogic) CreateOrder(ctx context.Context) error {
    tracer := otel.Tracer("biz")
    ctx, span := tracer.Start(ctx, "create-order")
    defer span.End()

    span.SetAttributes(
        attribute.Int64("order_id", orderId),
        attribute.String("operation", "create"),
        attribute.Float64("amount", amount),
    )

    // 记录事件
    span.AddEvent("payment-verified", trace.WithAttributes(
        attribute.String("method", "wechat"),
    ))

    // 记录错误
    if err != nil {
        span.RecordError(err)
        span.SetStatus(codes.Error, err.Error())
    }

    // 业务逻辑...
}

Prometheus 指标监控

内置指标(默认启用)

go-zero 自动暴露以下 Prometheus 指标:

指标名称 类型 说明
http_request_duration_ms Histogram 请求耗时分布
http_request_error_total Counter 错误请求计数

默认 buckets(毫秒):[5, 10, 25, 50, 100, 250, 500, 1000]

配置

Prometheus:
  Host: 0.0.0.0
  Port: 9090            # metrics 端口
  Path: /metrics

验证

# 访问 metrics 端点
curl http://localhost:9090/metrics

# 输出示例:
# http_request_duration_ms_bucket{path="/user/login",le="100"} 1523
# http_request_error_total{path="/user/login",code="500"} 2

禁用监控

Prometheus: false

Grafana 对接

  1. Prometheus 采集 go-zero 的 /metrics 端点
  2. Grafana 数据源配置为 Prometheus
  3. 导入或自建 Dashboard

推荐面板:

面板 PromQL
QPS rate(http_request_duration_ms_count[1m])
P99 延迟 histogram_quantile(0.99, rate(http_request_duration_ms_bucket[1m]))
错误率 rate(http_request_error_total[1m]) / rate(http_request_duration_ms_count[1m])

结构化日志

logx 配置

Log:
  ServiceName: user-api
  Mode: file
  Level: info
  Path: logs/user-api
  Encoding: json          # json | plain
  KeepDays: 7

使用

import "github.com/zeromicro/go-zero/core/logx"

// 基础使用
logx.Info("user created")
logx.Infof("user %d created", userId)
logx.Error("failed to create user")

// 带 context(自动注入 trace_id)
logx.WithContext(ctx).Infow("order created",
    logx.Field("orderId", orderId),
    logx.Field("userId", userId),
)

日志输出示例

启用 Telemetry 后,日志自动包含 tracespan 字段:

{
  "@timestamp": "2026-07-10T10:30:00.000Z",
  "level": "info",
  "content": "order created",
  "trace": "3e2a9bc1f...",
  "span": "abc123...",
  "orderId": 123,
  "userId": 456
}

💡 通过 trace_id 可以在 Jaeger 中查看完整调用链,也可以在 Loki/ELK 中按 trace_id 聚合日志。


内置中间件(全部默认启用)

go-zero 的 HTTP 和 RPC 服务默认启用以下可观测中间件:

中间件 功能 配置项
TraceHandler 链路追踪 Telemetry
PrometheusHandler 指标暴露 Prometheus
LogHandler 请求日志 Log
BreakerHandler 熔断 Breaker: true
MaxConnsHandler 并发限制 MaxConns
TimeoutHandler 超时控制 Timeout
SheddingHandler 过载降载 Shedding
RecoverHandler Panic 恢复 始终启用

💡 这些中间件自动生效,无需手动配置。你可以通过配置文件关闭或调整。


可观测性整体架构

                       ┌──────────────┐
                       │   Client     │
                       └──────┬───────┘
                              │ HTTP / gRPC
                       ┌──────▼───────┐
                       │  API Gateway │
            ┌──────────┤  (go-zero)   ├──────────┐
            │          └──────┬───────┘          │
            │                 │                   │
       /metrics          自动埋点            结构化日志
            │                 │                   │
     ┌──────▼──────┐   ┌─────▼─────┐     ┌──────▼──────┐
     │ Prometheus  │   │   OTLP    │     │  File/ELK/  │
     │  采集指标   │   │ Collector │     │    Loki     │
     └──────┬──────┘   └─────┬─────┘     └──────┬──────┘
            │                 │                   │
     ┌──────▼──────┐   ┌─────▼─────┐     ┌──────▼──────┐
     │   Grafana   │   │  Jaeger   │     │  Grafana    │
     │   监控面板  │   │ 链路追踪  │     │  日志面板   │
     └─────────────┘   └───────────┘     └─────────────┘

常见陷阱

陷阱 说明
🚨 OTLP 端口混淆 Jaeger v1.35 以前用 14268/14250,v1.35+ 统一用 4317/4318
🚨 生产环境全量采样 Sampler: 1.0 会显著增加 CPU 和网络开销
🚨 Jaeger batcher 已废弃 v1.10.0 起必须用 otlpgrpcotlphttp
🚨 Telemetry 配置缺失 缺少配置不会报错,但 trace 数据会静默丢失
🚨 logx.Info 不带 ctx 不使用 logx.WithContext(ctx) 会导致日志丢失 trace_id
🚨 Prometheus 端口冲突 多服务同机部署时注意 metrics 端口不要重复
🚨 过度自定义 Span 每个小函数都加 Span 反而影响性能,聚焦在关键业务节点