Nginx的ngx_http_addition_module本身不产生独立日志,但通过启用log_subrequest on;并配合internal指令和自定义日志格式,可使add_before_body/add_after_body触发的子请求被记录到access log中,实现可观测性。

Nginx 的 ngx_http_addition_module 本身不产生独立日志,它通过子请求(subrequest)注入内容,而子请求默认不会记录在 access log 中——它们是内部调用,不经过常规请求生命周期的日志写入环节。
但你可以通过组合配置和模块能力,间接实现对 addition 模块所触发子请求的可观测性。关键在于:让子请求“显形”并留下痕迹。
一、启用子请求日志记录(核心方法)
Nginx 提供了 log_subrequest on; 指令,它会让所有子请求(包括 add_before_body 和 add_after_body 发起的)被记录到 access log 中,前提是该子请求走完了完整的日志流程(即有明确的 status、uri、处理时长等)。
✅ 正确配置方式:
http {
log_format subreq '$remote_addr - $remote_user [$time_local] '
'"SUBREQ $request_method $uri $http_version" '
'$status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
access_log /var/log/nginx/subreq.log subreq;
log_subrequest on; # ← 必须开启!否则子请求完全静默
server {
listen 80;
server_name example.com;
location / {
add_before_body /_header;
add_after_body /_footer;
}
location = /_header {
internal; # ← 强制仅允许子请求访问(安全必需)
default_type text/html;
return 200 '<header>Site Header</header>';
}
location = /_footer {
internal;
default_type text/html;
return 200 '<footer>© 2026</footer>';
}
}
}⚠️ 注意:
-
log_subrequest on;必须放在http{}块中(全局生效),不能只在server或location中; - 子请求 URI(如
/_header)会以完整请求行形式出现在日志里,例如:SUBREQ GET /_header HTTP/1.0 -
internal;指令必须添加,防止外部直接访问这些子请求端点,否则可能被滥用或绕过缓存。
二、区分主请求与子请求日志(增强可读性)
默认日志无法直观判断某条日志是主请求还是子请求。可通过自定义变量 + map 实现标记:
http {
map $request_uri $is_subreq {
~^/_header|/_footer "1";
default "0";
}
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'subreq=$is_subreq rt=$request_time';
access_log /var/log/nginx/detailed.log detailed;
log_subrequest on;
}这样每条日志末尾都会带 subreq=1 或 subreq=0,便于 grep、ELK 过滤或 Prometheus 抓取。
三、验证子请求是否真正被记录
重启 Nginx 后,发起一次主请求(如 curl http://example.com/),然后检查日志:
tail -f /var/log/nginx/subreq.log
你应看到三条日志(典型情况):
- 一条主请求(
GET / HTTP/1.1) - 一条子请求(
SUBREQ GET /_header HTTP/1.0) - 一条子请求(
SUBREQ GET /_footer HTTP/1.0)
若只看到主请求,说明:
-
log_subrequest on;未生效(检查是否在http{}块内、是否 reload 成功); - 子请求 location 缺少
internal;或被其他规则拦截(导致未执行); -
add_before_body/add_after_body的 URI 返回非 2xx(Nginx 默认忽略失败子请求,也不记日志)。
四、补充可观测性(可选)
-
监控响应时间:子请求耗时会体现在
upstream_response_time字段中,可用于定位注入瓶颈; -
错误日志跟踪:在子请求 location 中加
error_log /var/log/nginx/addition.err notice;,配合ngx.log()(OpenResty)或简单return状态码调试; -
禁用缓存观察行为:临时加
add_header X-Addition-Debug "active";到子请求 location,方便 curl 验证是否命中。
不复杂但容易忽略:log_subrequest on; 是唯一打开子请求日志的开关,其余都是锦上添花。只要它开着,且子请求能正常返回,日志就自然出现。


















