4. Access Log 格式字符串详解:常用命令符与格式化选项
Envoy 的 Access Log 格式字符串由一系列命令符(Command Operators)和格式化选项组成。命令符以 % 包裹,用于从请求/响应中提取特定字段;格式化选项则控制字段的显示方式、长度、默认值等。掌握这些元素是定制高效、可读性强的日志格式的基础。
核心原则:命令符区分大小写,且必须严格遵循
%OPERATOR_NAME% 或 %OPERATOR_NAME(PARAMETER)% 的语法。Envoy 在解析格式字符串时,会从左到右依次替换每个命令符为实际值。
4.1 常用命令符分类与详解
命令符按数据来源可分为三大类:请求相关(%REQ%)、响应相关(%RESP%)和动态元数据(%DYNAMIC_METADATA%)。此外还有大量基础命令符用于获取时间、连接信息等。
| 类别 | 命令符 | 说明 | 典型输出示例 |
|---|---|---|---|
| 请求 | %REQ(X?Y):Z% |
提取请求头 X,若不存在则返回 Y,并截断为 Z 字符 |
GET / application/json |
%START_TIME% |
请求开始时间(ISO 8601 格式) | 2025-03-21T14:30:00.000Z |
|
%REQ_WITHOUT_QUERY% |
不带查询参数的请求路径 | /api/v1/users |
|
| 响应 | %RESP(X?Y):Z% |
提取响应头 X,若不存在则返回 Y,并截断为 Z 字符 |
200 / text/html |
%RESPONSE_CODE% |
HTTP 响应状态码 | 200 / 503 |
|
| 元数据 | %DYNAMIC_METADATA(NS:KEY):Z% |
从动态元数据中提取命名空间 NS 下的键 KEY,截断为 Z 字符 |
canary-v2 / 0.95 |
%METADATA(NS:KEY)% |
从静态元数据(Listener/Cluster 配置)中提取值 | us-east-1 |
|
| 连接 | %DOWNSTREAM_REMOTE_ADDRESS% |
下游客户端 IP 地址 | 10.0.0.1:54321 |
%UPSTREAM_HOST% |
上游目标主机地址 | 192.168.1.10:8080 |
|
| 时间 | %DURATION% |
整个请求处理耗时(毫秒) | 12 |
4.2 核心命令符深度解析
4.2.1 %REQ%:请求头提取器
%REQ(X?Y):Z% 是最常用的请求头提取命令符。其语法结构为:
- X:要提取的请求头名称(不区分大小写)。
- ?Y(可选):当请求头
X不存在时,返回的默认值。如果省略?Y且头不存在,则输出-。 - :Z(可选):最大字符截断长度。如果提取的值超过
Z个字符,则截断并追加..。
示例:
%REQ(USER-AGENT?unknown):50% → 提取 User-Agent 头,若不存在则输出 unknown,且最多保留 50 个字符。%REQ(AUTHORIZATION)% → 提取 Authorization 头,若不存在则输出 -。
4.2.2 %RESP%:响应头提取器
%RESP(X?Y):Z% 的语法与 %REQ% 完全一致,但提取的是响应头。注意:响应头仅在响应阶段可用,如果日志在请求阶段被刷新,则可能输出默认值。
避坑提示:对于
%RESP(X)%,如果上游未返回该响应头,且未指定默认值 ?Y,Envoy 会输出 -。这在调试时容易误判为“头被删除”,实际是上游未发送。
4.2.3 %DYNAMIC_METADATA%:动态元数据提取器
%DYNAMIC_METADATA(NS:KEY):Z% 用于提取 Envoy 在请求处理过程中动态附加的元数据。这些元数据通常由 RBAC 过滤器、外部授权(ExtAuthz)、Lua 过滤器或 Wasm 扩展写入。
- NS:元数据的命名空间(Namespace),通常与写入过滤器的名称一致。
- KEY:元数据中的具体键名,支持点号分隔的嵌套路径(如
auth.result)。 - :Z(可选):截断长度。
典型场景:
%DYNAMIC_METADATA(envoy.filters.http.ext_authz:auth.principal)% → 提取外部授权过滤器写入的认证主体信息。%DYNAMIC_METADATA(envoy.filters.http.rbac:shadow_engine_result)% → 提取 RBAC 影子模式下的评估结果。
4.3 格式化选项:控制输出精度
格式化选项通过 : 附加在命令符后,用于控制数值格式、时间格式和字符串长度。
| 格式化选项 | 适用命令符 | 说明 | 示例 |
|---|---|---|---|
:Z |
%REQ%, %RESP%, %DYNAMIC_METADATA% |
字符串截断为 Z 字符,超长部分以 .. 结尾 |
%REQ(HOST):20% → example.com 或 very-long-hostname... |
%START_TIME%:%s |
%START_TIME% |
Unix 时间戳(秒) | 1742555400 |
%START_TIME%:%f |
%START_TIME% |
Unix 时间戳(微秒) | 1742555400123456 |
%DURATION%:%f |
%DURATION% |
浮点数格式,保留微秒精度 | 12.345 |
%BYTES_RECEIVED%:Z |
%BYTES_RECEIVED% |
数字右对齐,最小宽度 Z |
%BYTES_RECEIVED%:10 → 1024 |
4.4 命令符组合与格式字符串构建
一个完整的 Access Log 格式字符串由多个命令符和分隔符(如空格、制表符 \t、竖线 |)拼接而成。Envoy 支持两种格式定义方式:
- 内联字符串:直接在配置文件中写
"%START_TIME% %REQ(X-METHOD)% %RESPONSE_CODE%"。 - 格式字符串文件:通过
access_log_format_string字段引用外部文件,便于管理和复用。
生产级格式示例:
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %UPSTREAM_HOST% "%REQ(USER-AGENT):50%" "%REQ(REFERER):50%" "%DYNAMIC_METADATA(envoy.filters.http.ext_authz:auth.principal)?-"
该格式包含了时间、请求行、状态码、响应标志、流量字节、耗时、上游地址、客户端信息以及外部授权元数据,适用于微服务网关的全面审计。
4.5 常见陷阱与最佳实践
陷阱 1:命令符大小写敏感
%req(X-My-Header)% 是无效的,必须写作 %REQ(X-My-Header)%。Envoy 只识别大写命令符名称。
陷阱 2:默认值中的特殊字符
如果默认值
如果默认值
?Y 中包含 ? 或 : 字符,需要使用反斜杠转义,例如 %REQ(X?question\?mark)%。
最佳实践:
- 始终为
%REQ%和%RESP%指定默认值,避免日志中出现大量-导致解析困难。 - 对长字符串(如
User-Agent)使用截断选项:Z,防止日志行过长影响存储和查询性能。 - 使用
%DYNAMIC_METADATA%时,确保命名空间与过滤器配置完全一致,否则输出始终为默认值。 - 在开发环境中先使用
%REQ(HEADER)%不带默认值,以便快速发现缺失的请求头。
4.6 实战:构建变更门禁审计日志格式
在变更门禁场景中,我们需要记录每个请求的变更操作类型、目标资源、审批状态以及执行用户。以下是一个针对门禁场景的格式字符串:
format_string: |
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%"
%RESPONSE_CODE% %RESPONSE_FLAGS%
user="%REQ(X-AUTH-USER?unknown)%"
action="%REQ(X-CHANGE-ACTION?none)%"
resource="%REQ(X-CHANGE-RESOURCE?none)%"
approval="%DYNAMIC_METADATA(envoy.filters.http.ext_authz:approval.status)?pending%"
duration=%DURATION%ms
upstream=%UPSTREAM_HOST%
字段说明:
X-AUTH-USER:由前置认证过滤器注入的请求头,标识操作人。X-CHANGE-ACTION和X-CHANGE-RESOURCE:客户端发送的变更意图。approval:从外部授权过滤器动态元数据中提取的审批状态,可能为approved、rejected或pending。duration:记录整个审批流程的耗时,用于性能监控。
通过上述格式,运维人员可以快速检索到所有 approval="rejected" 的日志行,定位被拒绝的变更请求及其原因。