Nginx捕获Trace-ID需两步:开启underscores_in_headers on以支持下划线Header;用map指令安全映射$http_x_trace_id为$trace_id,再写入log_format,并通过proxy_set_header透传至后端。

要在 Nginx 日志中捕获自定义 Header(如 Trace-ID)并用于全链路追踪,核心是两步:一是让 Nginx 接收并保留上游传来的 TraceID,二是将它写入 access_log。这不需要改代码,靠配置就能实现,但有几个关键细节容易出错。
确保 Nginx 正确接收并透传 TraceID Header
Nginx 默认会过滤掉下划线(_)和部分非标准字符的 Header,而很多业务用的 TraceID 名为 X-Trace-ID 或 trace-id,属于合法命名;但如果用了 X_Trace_ID(含下划线),Nginx 会直接丢弃——这是最常见的日志为空原因。
解决办法是在 http 或 server 块中显式开启下划线支持:
underscores_in_headers on;
同时确认上游服务(如 Spring Cloud Gateway、Node.js 网关或客户端)确实设置了该 Header,可用 curl 验证:
curl -H "X-Trace-ID: abc123" http://your-nginx-host/health
在 log_format 中定义并引用自定义变量
不能直接在 log_format 里写 $http_x_trace_id 就完事——如果请求没带这个 Header,Nginx 会记为空字符串,但日志里会出现大量空白字段,影响 grep 和日志平台检索。
推荐做法是用 map 指令做安全映射,把缺失值统一转为短标识(如 - 或 NA):
map $http_x_trace_id $trace_id {
"" "-";
default $http_x_trace_id;
}然后在 log_format 中引用:
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$trace_id;'注意:$http_x_trace_id 是 Nginx 内置变量,自动将 Header 名转为小写 + 下划线格式(X-Trace-ID → $http_x_trace_id,trace-id → $http_trace_id)。
配合 upstream 实现跨服务透传(可选但推荐)
如果 Nginx 充当反向代理,还需把 TraceID 透传给后端服务,否则链路在 Nginx 就断了。用 proxy_set_header 即可:
location /api/ {
proxy_pass http://backend;
proxy_set_header X-Trace-ID $trace_id;
# 也可透传原始值(不走 map):
# proxy_set_header X-Trace-ID $http_x_trace_id;
}这样后端服务也能拿到并继续向下传递,真正形成「全链路」。
验证与日志检索建议
改完配置后必须重载:
nginx -t && nginx -s reload
接着发带 TraceID 的请求,检查 access.log 是否出现对应值:
tail -f /var/log/nginx/access.log | grep "abc123"
生产环境建议:
- 日志字段用固定分隔符(如
|或\t),避免空格干扰结构化解析; - 在 ELK 或 Loki 中为
trace_id字段建立索引,支持毫秒级检索; - 对内部调用(如健康检查、监控探针)可忽略 TraceID,避免污染日志,用
if ($request_uri ~ ^/health) { set $trace_id "-"; }控制。


















