API 网关日志分析应当回答运维问题,而不只是收集访问记录。有效的设计会把一次客户端操作与网关准入、上游尝试、应用结果和配置变更关联起来,同时让日志缺失或延迟本身也可见。
网关观测到的是一个重要边界,但不是全部。网关返回 200 并不能证明业务事务已经完成,超时也不能证明上游没有执行任何操作。在得出结论前,应把网关证据与应用拥有的业务结果关联起来。
核心要点
- 先设计稳定的事件 Schema,再选择 Dashboard 或存储技术。
- 把关联 ID、已认证身份与业务标识符分开。
- 记录决策原因、上游尝试、延迟组成、字节数与配置版本。
- 发现日志管道自身的丢失、积压、截断与 Schema 漂移。
- 从运维问题出发设计查询,并为每个信号指定负责人和响应动作。
- 默认关闭请求体与响应体日志;只有范围很窄且经过审查的用例才应开启。
划定边界:存储、审计与分析
这些能力彼此相关,但不能互换:
- 日志投递与存储负责可靠搬运记录、分区、留存与访问控制。
- 审计日志保存与安全相关动作的证据,并关注完整性、留存与审查。
- 日志分析对事件进行分组和关联,用来解释行为、发现变化并指导响应。
- 指标提供有边界的数值时间序列,适合告警与趋势分析。
- Trace在传播与采样正确时,连接跨组件的因果操作。
建立在尽力而为访问日志上的分析 Dashboard,并不会自动成为审计系统。同样,如果字段无法区分网关拒绝和上游失败,即使 Archive 很耐久,对运维也没有足够帮助。
围绕问题建立事件模型
先列出运维人员必须回答的问题:
| 问题 | 最少需要的网关字段 | 由其他系统负责的字段 |
|---|---|---|
| 哪条 Route 正在失败? | Route/Service ID、状态、网关错误分类、时间戳 | 应用错误码 |
| 延迟花在哪里? | 网关延迟、上游延迟、尝试次数 | 队列与应用 Span |
| 谁被允许或拒绝? | 认证结果、Consumer 或 Subject 引用、策略原因 | 权威身份生命周期 |
| 是否由发布引起? | 网关配置或发布版本、选中的上游 | 应用 Build 与 Feature Flag |
| 业务操作是否成功? | 请求与关联上下文 | 持久的订单、支付或工作流状态 |
| 滥用是否在消耗容量? | 身份、Route、字节数、限速决定、来源上下文 | 账户风险与业务影响 |
聚合时优先使用稳定 ID,把便于阅读的名称作为查询表数据。不要把原始 URL、无限制的 User-Agent、账户 ID 或任意错误文本放进指标 Label。日志可以在访问与留存控制下携带更高 Cardinality 字段。
做好关联,但不要虚构信任
不同目的应使用不同标识符:
- 网关请求 ID:表示边界上的一次请求;
- Trace ID:表示一次经过采样的分布式执行;
- 已认证 Subject 或 Consumer 引用:表示安全上下文;
- 应用操作或 Idempotency Key:表示一次业务动作;
- 网关配置或发布 ID:表示变更归因。
Apache APISIX 3.19.0 的 request-id 插件会保留配置 Header 中已有的非空值;只有在 Header 缺失或为空时才生成新值。因此,请求 ID 适合作为关联上下文,但它不是可信身份;在调用方可提供时,也不能保证全局唯一。如果它会被索引,应在边界验证长度与字符集。
插件的 include_in_response 默认为 true。true 路径通过配置的响应 Header 返回请求 ID,方便客户端反馈;false 路径仍会转发并记录 ID,但不会在响应中暴露。两条路径都不会认证调用方。
输出最小、有界的记录
下面的 Apache APISIX 3.19.0 摘录启用请求 ID,并向 HTTPS Collector 发送一个刻意精简的 JSON 日志。它不是完整部署:Collector 认证、CA 信任、重试、容量、存储 Schema、脱敏与告警需要另行设计。
1{
2 "uri": "/orders/*",
3 "plugins": {
4 "request-id": {
5 "header_name": "X-Request-Id",
6 "include_in_response": true
7 },
8 "http-logger": {
9 "uri": "https://logs.internal.example/v1/gateway",
10 "ssl_verify": true,
11 "include_req_body": false,
12 "include_resp_body": false,
13 "log_format": {
14 "event_time": "$time_iso8601",
15 "request_id": "$apisix_request_id",
16 "route_id": "$route_id",
17 "consumer_name": "$consumer_name",
18 "method": "$request_method",
19 "status": "$status",
20 "request_time": "$request_time",
21 "upstream_time": "$upstream_response_time",
22 "bytes_sent": "$bytes_sent"
23 }
24 }
25 },
26 "upstream_id": "orders-v2"
27}http-logger 插件的 include_req_body 与 include_resp_body 默认都为 false,因此对应 Payload 不会进入日志。使用默认日志格式时,把任一选项设为 true,符合条件的 Body 才可能被记录;它仍受条件、NGINX 缓冲限制和默认 524,288 字节的单个 Body 上限约束,超过上限的日志内容会被截断。本例使用自定义 log_format:只把任一开关设为 true,仍不会在这条日志中增加 Body 字段。如果经过审查的用例需要请求体,官方文档把 $request_body 列为可以显式加入格式的字段;应在所选部署中验证其可用性与限制。开启 Body 日志可能捕获 Token、个人数据、支付数据或大型 Payload,因此只能在范围很窄且条件经过审查的 Route 上启用。
在 APISIX 3.19.0 的 http-logger 中,ssl_verify 默认为 false。false 路径虽然使用 TLS,却不验证 Collector 证书;true 路径使用配置的信任来验证证书。本例明确选择 true。证书验证保护的是 Collector 连接,不能证明每个日志字段都具有权威性。
插件会以 Batch 方式投递。其全局元数据 max_pending_entries 默认为 8192;当积压超过该限制时,会丢弃新 Entry,以限制 Worker 内存。因此,网关响应可能成功,而对应日志已经丢失。应监控 Collector 可用性与投递丢失;如果没有独立验证的设计,就不能把尽力而为传输描述成完整审计证据。
查询前先规范化
在摄取阶段验证 Schema,并添加 Environment、Region、网关实例、Schema 版本与配置版本等受控元数据。审计要求需要时,可以保留原始事件或其加密引用,但查询应使用规范化的类型字段。
常见派生字段包括:
- 状态类别与规范化的网关错误分类;
- 单位一致的总延迟、网关延迟与上游延迟;
- 尝试次数与选中的上游;
- 已准入、已拒绝、已限速或上游前失败的结果;
- 入站与出站字节数;
- 已认证 Principal 引用与凭据类型;
- 部署、Canary 与策略版本;
- 日志到达延迟与管道来源。
缺失值应与零分开。上游延迟缺失,可能表示代理前就被拒绝、连接失败、日志变体或输入格式错误。不要把所有缺失值都转换为零延迟的上游调用。
把查询转化为运维信号
下面是一段针对假设规范化表的 ClickHouse 示例查询。应根据实际 Schema 调整字段名与类型;它不是 APISIX 内置 Schema。
1SELECT
2 toStartOfFiveMinutes(event_time) AS bucket,
3 route_id,
4 count() AS requests,
5 countIf(status >= 500) AS server_errors,
6 quantile(0.95)(request_time_ms) AS p95_ms
7FROM gateway_logs
8WHERE event_time >= now() - INTERVAL 1 HOUR
9GROUP BY bucket, route_id
10ORDER BY bucket, route_id;该查询能发现 Route 级变化,但告警仍需设置最小流量、错误比例或服务等级目标,并指定负责人和 Runbook。五次错误在十次请求和一千万次请求中的含义完全不同。
可以围绕以下主题建立查询族:
- **可用性:**按 Route 与网关结果统计错误比例,并与客户端错误分开。
- **延迟:**将网关和上游延迟拆开计算 Percentile,同时显示流量。
- **饱和度:**并发、连接压力、准入拒绝,以及队列或 Logger 积压。
- **安全:**认证与策略拒绝原因、可疑的凭据或来源轮换,以及绕过尝试。
- **变更影响:**按配置、上游、Region 或 Canary Cohort 比较变更前后结果。
- **成本:**字节数、重试次数、高成本 Route 类别与遥测量。
发现管道失败与数据漂移
把日志本身当作一个数据产品来监控:
- 在有边界的时间窗口内,对比网关请求计数与收到的日志数;
- 同时记录事件时间与摄取时间,以暴露延迟;
- 拒绝或隔离无效 Schema 版本,而不是静默丢字段;
- 跟踪关键字段的 Null 比例与 Cardinality 变化;
- 注入安全的合成请求,并验证其记录能到达查询层;
- 测试 Collector 故障、积压耗尽、恢复和重复投递;
- 说明重试是否会生成重复日志,以及查询如何去重。
没有错误日志,并不能证明没有发生错误。Collector 故障期间,Dashboard 反而可能因为失败事件停止到达而显得更健康。
保护敏感数据
只收集能够回答运维或审计问题的最少数据。排除 Authorization Header、Cookie、Secret、完整 Token 与未经审查的 Body。即使对邮箱或账户编号做 Hash,数据仍可能被关联,应遵循组织的隐私分类与留存规则。
运维汇总与原始安全事件应采用不同的访问权限。对敏感数据集的查询与导出操作进行记录。实际测试删除、Legal Hold 与留存 Tier 迁移,不要假设存储策略已经正确生效。
日志分析检查清单
- 每个字段是否都有类型、负责人、含义与敏感度分类?
- 请求 ID、Trace ID、已认证身份与业务操作是否彼此分开?
- 记录能否区分上游前拒绝、上游失败与应用拒绝?
- Body 日志是否写明默认值、
true/false路径、自定义格式行为、大小上限与截断行为? - Collector TLS 证书验证是否明确?
- 积压、丢弃、延迟、重复和 Schema 失败路径是否可观测?
- 每个告警是否包含流量背景、负责人和响应动作?
- 得出业务结论前,是否把网关结果与应用结果关联起来?
- 留存、访问、脱敏与删除是否经过测试?
常见问题
每个请求都应该记录吗?
不一定。安全或法规证据可能要求特定事件的完整记录;高流量运维分析则可能采用有边界的采样或聚合。应按字段和事件类别定义要求,再测试丢失与采样行为。
请求 ID 可以作为用户身份吗?
不可以。它只是关联上下文,而且 APISIX 会保留调用方提供的非空值。应使用由配置的认证路径建立的身份,并单独保留其来源。
日志足以实现 API 可观测性吗?
不足以。指标更适合有边界的时间序列告警,Trace 可以连接经过采样的跨服务工作,应用状态则确定业务结果。日志提供详细事件,用于补充这些信号。
后续步骤
把本模型与 API 网关日志存储、API 访问日志审计和API 网关超时与重试结合使用。
