4、Envoy 访问日志格式配置:默认格式、JSON 格式、自定义格式、日志字段详解

Envoy 访问日志是服务网格可观测性的核心数据源,记录了每个请求的完整生命周期。掌握日志格式配置,是进行流量拓扑分析和故障排查的基础。Envoy 支持三种日志格式:默认格式(字符串)、JSON 格式(结构化)和自定义格式(混合模式)。

生产建议: 在服务网格生产环境中,强烈推荐使用 JSON 格式。结构化日志可直接被 Elasticsearch、Loki、Splunk 等日志平台解析,便于后续的拓扑聚合和故障链路追踪。

4.1 默认格式(Default Format)

Envoy 默认使用 ENVOY_DEFAULT_FORMAT 字符串格式,包含 14 个核心字段,以空格分隔。该格式适合快速查看,但解析效率低,不推荐用于生产。

[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n

示例输出:

[2025-04-10T08:12:34.567Z] "GET /api/v1/products HTTP/1.1" 200 - 0 1234 567 89 "10.0.0.1" "curl/7.68.0" "abc-123-def" "product-service.default.svc.cluster.local" "10.0.0.2:8080"

4.2 JSON 格式(JSON Format)

JSON 格式将日志输出为结构化的 JSON 对象,每个字段有明确的键名。这是服务网格可观测性的标准格式。

{
  "start_time": "2025-04-10T08:12:34.567Z",
  "method": "GET",
  "path": "/api/v1/products",
  "protocol": "HTTP/1.1",
  "response_code": 200,
  "response_flags": "-",
  "bytes_received": 0,
  "bytes_sent": 1234,
  "duration": 567,
  "upstream_service_time": 89,
  "x_forwarded_for": "10.0.0.1",
  "user_agent": "curl/7.68.0",
  "request_id": "abc-123-def",
  "authority": "product-service.default.svc.cluster.local",
  "upstream_host": "10.0.0.2:8080"
}

配置示例(Envoy YAML):

access_log:
- name: envoy.access_loggers.file
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
    path: /dev/stdout
    log_format:
      json_format:
        start_time: "%START_TIME%"
        method: "%REQ(:METHOD)%"
        path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
        protocol: "%PROTOCOL%"
        response_code: "%RESPONSE_CODE%"
        response_flags: "%RESPONSE_FLAGS%"
        bytes_received: "%BYTES_RECEIVED%"
        bytes_sent: "%BYTES_SENT%"
        duration: "%DURATION%"
        upstream_service_time: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%"
        x_forwarded_for: "%REQ(X-FORWARDED-FOR)%"
        user_agent: "%REQ(USER-AGENT)%"
        request_id: "%REQ(X-REQUEST-ID)%"
        authority: "%REQ(:AUTHORITY)%"
        upstream_host: "%UPSTREAM_HOST%"

4.3 自定义格式(Custom Format)

自定义格式允许混合使用字符串和字段占位符,适用于需要特定分隔符或前缀的场景。Envoy 使用 format 字段定义。

access_log:
- name: envoy.access_loggers.file
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
    path: /dev/stdout
    log_format:
      format: "[%START_TIME%] %REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% -> %RESPONSE_CODE% (%DURATION%ms)\n"

示例输出:

[2025-04-10T08:12:34.567Z] GET /api/v1/products -> 200 (567ms)

4.4 日志字段详解

Envoy 访问日志字段可分为 6 大类:时间、请求、响应、连接、上游、动态元数据。下表列出故障排查中最关键的 20 个字段:

分类 字段名 占位符 说明 故障排查用途
时间 开始时间 %START_TIME% 请求开始处理的 UTC 时间 时间窗口对齐、延迟基线
持续时间 %DURATION% 请求总耗时(毫秒) 延迟分析、P99 计算
请求 方法 %REQ(:METHOD)% HTTP 方法(GET/POST/PUT/DELETE) 请求类型过滤
路径 %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% 原始请求路径(优先取 x-envoy-original-path) 路由匹配、404 排查
协议 %PROTOCOL% HTTP 协议版本(HTTP/1.1、HTTP/2、HTTP/3) 协议兼容性检查
请求 ID %REQ(X-REQUEST-ID)% Envoy 自动生成的请求追踪 ID 跨服务请求关联
响应 响应码 %RESPONSE_CODE% HTTP 响应状态码 错误率、5xx 告警
响应标志 %RESPONSE_FLAGS% Envoy 内部响应标志(如 UH、UF、URX、DC) 连接池耗尽、熔断、超时诊断
发送字节数 %BYTES_SENT% 响应 Body 字节数 大响应体排查
上游服务时间 %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% 上游服务实际处理耗时(毫秒) 区分网络延迟 vs 服务处理延迟
连接 客户端 IP %REQ(X-FORWARDED-FOR)% 原始客户端 IP(通过 X-Forwarded-For 传递) 客户端来源识别
User-Agent %REQ(USER-AGENT)% 客户端 User-Agent 头 客户端类型识别
Authority %REQ(:AUTHORITY)% 请求的 Host 头 虚拟主机路由匹配
上游 上游主机 %UPSTREAM_HOST% 上游 Pod IP:Port 流量分发、Pod 级故障定位
上游集群 %UPSTREAM_CLUSTER% 上游集群名称 集群级流量拓扑
上游传输失败原因 %UPSTREAM_TRANSPORT_FAILURE_REASON% 上游连接失败的具体原因 TLS 握手失败、连接拒绝诊断
动态 动态元数据 %DYNAMIC_METADATA(envoy.filters.http.router:vcluster)% 从动态元数据中提取指定键值 自定义路由/限流策略追踪
过滤器状态 %FILTER_STATE(wasm.test:value)% 从过滤器状态中提取数据 Wasm 扩展、自定义逻辑调试
关键字段解读:
  • %RESPONSE_FLAGS%:这是故障排查的“第一现场”。例如 UH 表示上游集群无健康主机,UF 表示上游连接失败,URX 表示上游请求超时,DC 表示下游连接断开。
  • %UPSTREAM_HOST%:直接显示请求被路由到的具体 Pod IP,是流量拓扑分析的核心字段。
  • %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%:与 %DURATION% 对比,可快速判断延迟是发生在网络层还是服务层。

4.5 日志格式选择决策流程

以下流程图帮助你在不同场景下选择合适的日志格式:

Envoy 访问日志格式选择决策流程 开始配置日志格式 是否需要结构化日志? 是 使用 JSON 格式 是否需要自定义字段名? 是 自定义 JSON 字段映射 否 使用默认 JSON 配置完成 否 自定义字符串格式

4.6 日志字段与流量拓扑的映射关系

在服务网格流量拓扑分析中,Envoy 日志字段直接映射到拓扑图的各个元素:

拓扑元素 对应日志字段 说明
源服务 %REQ(:AUTHORITY)% + %REQ(X-REQUEST-ID)% 通过 Authority 识别目标服务,Request ID 关联调用链
目标服务 %UPSTREAM_CLUSTER% Envoy 路由到的上游集群名称
目标实例 %UPSTREAM_HOST% 具体的 Pod IP:Port
调用延迟 %DURATION% + %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% 总延迟 vs 服务处理延迟
错误状态 %RESPONSE_CODE% + %RESPONSE_FLAGS% HTTP 状态码 + Envoy 内部标志
流量路径 %REQ(X-FORWARDED-FOR)% + %UPSTREAM_HOST% 客户端 IP → 上游 Pod 的完整路径
常见陷阱:
  • 字段顺序依赖: 默认格式的字段顺序是固定的,如果自定义格式改变了顺序,日志解析脚本必须同步更新。
  • JSON 字段名大小写: Envoy 的 JSON 格式字段名默认小写,如果使用 Elasticsearch 等区分大小写的存储,需注意字段名一致性。
  • %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% 的优先级: 当请求经过多个 Envoy 时,x-envoy-original-path 头会保留原始路径,避免内部重写导致路径丢失。

4.7 实战:快速切换日志格式

在 Istio 环境中,可以通过 istioctl 或 kubectl 动态修改 Envoy 日志格式,无需重启 Pod:

# 查看当前 Envoy 日志配置
istioctl proxy-config log <pod-name>.<namespace>

# 动态切换为 JSON 格式(临时生效,Pod 重启后恢复)
istioctl proxy-config log <pod-name>.<namespace> --level default:info --format json

# 持久化修改(通过 EnvoyFilter 或 Sidecar 配置)
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: access-log-json
  namespace: istio-system
spec:
  configPatches:
  - applyTo: NETWORK_FILTER
    match:
      context: ANY
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: MERGE
      value:
        typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
          access_log:
          - name: envoy.access_loggers.file
            typed_config:
              "@type": "type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog"
              path: /dev/stdout
              log_format:
                json_format:
                  start_time: "%START_TIME%"
                  method: "%REQ(:METHOD)%"
                  path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
                  response_code: "%RESPONSE_CODE%"
                  response_flags: "%RESPONSE_FLAGS%"
                  duration: "%DURATION%"
                  upstream_host: "%UPSTREAM_HOST%"
EOF
故障排查速查:
  • 延迟高: 对比 %DURATION% 和 %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%,差值大说明网络/Envoy 处理延迟高。
  • 5xx 错误: 查看 %RESPONSE_FLAGS% 是否为 UH(无健康上游)或 UF(连接失败)。
  • 流量不均衡: 聚合 %UPSTREAM_HOST% 字段,统计每个 Pod 接收的请求数。
  • 请求丢失: 检查 %RESPONSE_FLAGS% 是否为 DC(下游断开)或 URX(上游超时)。