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 日志格式选择决策流程
以下流程图帮助你在不同场景下选择合适的日志格式:
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(上游超时)。