最高效的方式是用 log_if 配合 map 在写入前过滤异常状态码。推荐仅记录 2xx/3xx 成功响应,4xx/5xx 不进主日志;可选将异常单独输出至 error_only.log;支持精准排除如 502/504 而保留 401/403;配置后需 nginx -t 验证并 reload 生效。

直接用 log_if 配合 map 按状态码过滤异常访问,是最高效、低开销的方式。重点不是把日志写进去再删,而是在写入前就决定“哪些状态不该记”。
只记录非异常状态(推荐)
让 Nginx 仅对成功或预期状态(如 200、301、302)写日志,自动跳过 4xx/5xx:
- 在
http块顶部定义判断变量:
map $status $loggable {
~^[23] 1;
default 0;
} - 将主日志指令改为:
access_log /var/log/nginx/access.log main if=$loggable; - 这样所有 400、404、500、502 等异常响应都不会进入主日志,磁盘和分析负担显著下降
单独隔离异常状态到独立文件
如果需要保留异常请求做分析(比如监控错误率或定位故障),可将其导出到专用日志:
- 定义异常专用日志格式(精简字段,便于快速扫描):
log_format error_only '$time_local $remote_addr "$request" $status $body_bytes_sent $request_time'; - 用 map 标记异常状态:
map $status $is_error {
~^[45] 1;
default 0;
} - 添加独立日志行:
access_log /var/log/nginx/error_only.log error_only if=$is_error;
排除特定异常但保留其他
有些异常是预期行为(如 API 返回 401/403),不应被过滤;而像 502/504 这类网关错误才需重点关注:
- 精准排除后端故障类状态:
map $status $log_backend_fail {
"502" 0;
"504" 0;
default 1;
} - 配合使用:
access_log /var/log/nginx/access.log main if=$log_backend_fail; - 这样 502/504 不进主日志,但 404、403 仍保留,兼顾排障与日志瘦身
验证是否生效
改完配置别忘了验证:
- 运行
nginx -t检查语法,再nginx -s reload平滑生效 - 手动触发一次 502:
curl -I http://your-domain.com/bad-upstream - 检查主日志是否无新增,同时确认
error_only.log或对应文件中是否有该条目 - 用
tail -f /var/log/nginx/access.log | grep " 502 "实时观察











