nginx 无法直接按状态码自动归档日志,但可通过 map 模块标记 4xx/5xx 状态码,配合条件 access_log 分离记录,并借助 logrotate 实现压缩、轮转及 usr1 重载;亦可用 awk 从历史日志中提取特定状态码并定时归档。

在 Nginx 中,不能直接对“特定状态码”自动触发日志归档(如压缩、移动或切割),但可以通过组合 log_format、access_log 条件记录 + 外部脚本(如 logrotate 或自定义定时任务)实现按状态码分类归档的目标。
用 map 模块标记特定状态码请求
先定义一个变量,将 404、500、502 等关注的状态码单独标记出来,便于后续过滤或分流日志:
map $status $is_error_code {
~^[45][0-9]{2}$ 1; # 匹配所有 4xx 和 5xx
default 0;
}
这个变量可在 log_format 中使用,也可用于 if 判断(注意:if 在 location 中慎用,但用于 access_log 的条件写法是安全的)。
为特定状态码单独写入日志文件
利用 access_log 的条件写法,只把匹配的状态码写进独立文件:
access_log /var/log/nginx/error_code.log main if=$is_error_code; access_log /var/log/nginx/access.log main;
- 这样所有 4xx/5xx 请求会同时记入
error_code.log和常规日志 - 若只想单独记录(不重复写主日志),可去掉第二行,或用
if=$is_error_code控制主日志是否写入 - 支持多个 map 变量,例如单独标记
404或502,再对应不同日志路径
配合 logrotate 实现归档与压缩
Nginx 自身不管理日志生命周期,需依赖系统工具。以 /var/log/nginx/error_code.log 为例,在 /etc/logrotate.d/nginx 中添加:
/var/log/nginx/error_code.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0644 www-data www-data
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
-
compress启用 gzip 压缩归档文件 -
postrotate发送 USR1 信号通知 Nginx 重新打开日志文件(避免写入旧文件) - 确保 Nginx 运行用户(如 www-data)对日志目录有读写权限
高级:用脚本提取并归档历史状态码日志
如果已有大量访问日志,想从中提取某类状态码做离线分析或归档,可用 awk 快速筛选:
# 提取所有 502 请求并保存为新文件
awk '$9 == "502" {print}' /var/log/nginx/access.log > /var/log/nginx/502_archive_$(date +%Y%m%d).log
<h1>压缩并清理原始大日志(谨慎执行)</h1><p>gzip /var/log/nginx/502<em>archive</em>*.log</p>- 字段 $9 是默认日志格式中的 status 字段;若用了自定义 log_format,需确认状态码所在列数
- 可将该命令写入 cron 定时任务,每天凌晨执行一次
- 建议先测试 awk 表达式,避免误删或漏提











