关键不是删日志,而是让nginx写入前跳过无意义轮询请求;用map定义$skip_log变量,匹配/healthz等路径、200状态码及低耗时,实现精准过滤。

直接用 map 过滤高频 200 日志、保留真正异常,关键不是“删日志”,而是让 Nginx 在写入前就跳过那些无意义的轮询请求——只留有价值的错误线索。
识别并标记高频静态轮询请求
轮询类请求(如 /healthz、/ping、/status)通常特征固定:路径明确、方法为 GET/HEAD、响应恒为 200、且单位时间频次极高。用 map 提取这些特征组合成一个开关变量:
- 定义变量
$skip_log,匹配健康检查路径 + 200 状态码 + 低耗时(1 - 注意:
$status在map中可用,但必须确保该map块位于http{}块内,且在log_format和access_log之前加载 - 示例配置:
map "$request_uri:$status:$request_time" $skip_log { default 0; ~^/healthz:200:[0-9]{1,3}(\.[0-9]+)? 1; ~^/ping:200:[0-9]{1,3}(\.[0-9]+)? 1; }
用 if 控制 access_log 写入条件
access_log 的 if= 参数只认“非空且非 0”的值,因此只需把 $skip_log 反向使用即可:
- 写日志时加
if=$skip_log是错的(它会记录被标记的请求);正确写法是if=$skip_log设为 0 才记录,所以应改用否定逻辑 - 更稳妥做法:另建一个变量
$log_it,值为1表示需要记录,其余为""(空字符串),Nginx 会自动跳过 - 配置片段:
map "$skip_log" $log_it { "0" "1"; default ""; } server { access_log /var/log/nginx/access.log main if=$log_it; }
确保关键错误不被误过滤
200 轮询要过滤,但某些“表面 200 实则异常”的请求必须保留,比如:
- 大请求体返回 200(
$request_length > 10M且$status == 200)——可能绕过限制上传恶意文件 - 业务接口返回 200 但响应体极小(
$body_bytes_sent )——疑似失败却伪装成功 - 解决办法:在
map中优先匹配这些高危组合,强制设$log_it = "1",覆盖轮询规则 - 例如扩展 map:
map "$request_uri:$status:$request_length:$body_bytes_sent" $log_it { ~^.+:200:[0-9]{7,}:.* "1"; # 请求超大 ~^.+:200:[0-9]+:[0-4][0-9] "1"; # 响应体太小 ~^/healthz:200:.* ""; ~^/ping:200:.* ""; default "1"; }
配合日志格式突出异常信号
光过滤不够,还要让留下的日志自带诊断信息:
- 自定义
log_format,显式加入$request_length、$body_bytes_sent、$request_time - 对疑似异常请求,在日志中加标记字段,比如用另一个
map输出"ALERT"或"SKIPPED" - 这样在 ELK 或 grep 查看时,能一眼区分:是真错误,还是被策略放过的轮询











