log_subrequest on可开启子请求日志,需在http或server块中配置,配合$request_id和$subrequest变量区分主/子请求,适用于SSI、rewrite last、try_files等内部转发场景。

要通过 log_subrequest 开启子请求日志来深度追踪 SSI(Server Side Include)和内部转发(如 internal redirect、rewrite、try_files 等触发的子请求),核心在于正确配置 Nginx 的日志模块与请求上下文标识能力——因为默认 access log 不记录子请求,必须显式启用并配合自定义日志格式区分主/子请求。
启用 log_subrequest 并确认模块可用
Nginx 1.19.4+ 原生支持 log_subrequest on,但需确保使用的是官方主线版本或已启用该功能的发行版(如某些 OpenResty 版本可能默认关闭)。检查方式:
- 运行
nginx -V 2>&1 | grep -o 'with-http-log-module',确认日志模块已编译 - 在
http或server块中添加:log_subrequest on; - 注意:该指令仅控制是否将子请求写入 access_log,不改变日志内容本身
定义可区分主/子请求的日志格式
关键是要在日志中体现请求层级关系。推荐在 log_format 中加入 $request_id 和 $pid,并用 $request_completion 或自定义变量标记是否为子请求:
- 启用唯一请求 ID:
map $request_id $is_subrequest { "" "0"; default "1"; }
(配合ngx_http_core_module的$request_id变量,需在 server 块中设random_index on;或用more_set_headers "X-Request-ID: $request_id";触发生成) - 更可靠的做法是用
$request_length或$connection_requests辅助判断,但最直接的是借助第三方模块如ngx_http_request_id_module或 OpenResty 的resty.requestid - 示例日志格式:
log_format trace '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" req_id="$request_id" sub="$is_subrequest" parent="$upstream_http_x_request_id"'
配合 SSI 与内部转发的实际追踪技巧
SSI 包含(<!--# include virtual="/fragment.html" --> )会发起子请求;rewrite ... last、try_files ... =404、error_page 404 /fallback 等也会触发内部子请求。要清晰追踪链路:
- 对 SSI 资源单独配置 location,开启
log_subrequest on并打标:location /fragment.html { log_subrequest on; add_header X-Request-ID $request_id; } - 在主 location 中透传请求 ID 给子请求:
proxy_set_header X-Request-ID $request_id;(若用 proxy_pass)或fastcgi_param HTTP_X_REQUEST_ID $request_id;(若用 fastcgi) - 对 rewrite 后的内部跳转,可通过
$request_uri与$uri差异识别——子请求的$uri是重写后的路径,而$request_uri保持原始值,可在日志中并列输出两者
验证与调试建议
开启后不要只依赖日志文件滚动查看,应结合实时过滤提升效率:
- 用
tail -f /var/log/nginx/access.log | grep -E '(sub="1"|/fragment\.html)'实时捕获子请求 - 用
curl -H "X-Request-ID: test123" http://localhost/page.html手动注入 ID,便于在日志中快速定位整条调用链 - 注意:SSI 子请求默认共享父请求的 client IP 和 user agent,如需独立记录,需在子 location 中覆盖
$remote_addr等变量(较复杂,通常不必要) - 若发现子请求未被记录,请检查是否被
location ~ \.html$ { log_subrequest off; }类规则覆盖——log_subrequest遵循 location 匹配优先级

















