01. access_log——记录每个请求
access_log 记录每一个请求的详细信息——谁在什么时间访问了什么资源、返回了什么状态码、传输了多少数据。这些日志是做数据分析、排查问题、安全审计的基础。
默认的 combined 格式挺全的:客户端 IP、时间、请求行、状态码、响应大小、Referer、User-Agent。
自定义 log_format 可以加更多信息:$request_time(请求处理时间)、$upstream_response_time(后端响应时间)、$upstream_addr(后端地址)、$http_x_forwarded_for(真实客户端 IP,在代理后面特别重要)。
access_log 的路径和是否开启可以针对每个 server 或 location 单独设置。off 关掉日志(对健康检查等频繁请求可以关掉减少 IO)。
nginx
# 自定义日志格式
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $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/access.log main;
# 按 location 关闭日志
location /health {
access_log off;
return 200;
}$request_time vs $upstream_response_time——前者是 Nginx 从收到请求到响应的总时间,后者是后端的处理时间。差值太大说明 Nginx 自己处理(如静态文件)或网络传输花了时间。
02. error_log——记录错误与调试
error_log 记录 Nginx 遇到的错误、警告和调试信息。错误日志级别从低到高:debug、info、notice、warn、error、crit、alert、emerg。
生产环境通常设 warn 或 error 级别。设 debug 级别日志量爆炸且有性能影响,只用于排查具体问题(需要编译 Nginx 时加上 --with-debug 支持)。
error_log 可以配置到文件、syslog、或者 stderr(容器里常用,日志收集系统统一收)。
常见的 error_log 里的问题:
upstream timed out——后端响应超时。
connect() failed——连不上后端。
SSL 相关错误——证书配置问题。
permission denied——文件权限问题。
nginx
# 错误日志配置
error_log /var/log/nginx/error.log warn;
# 输出到 syslog
error_log syslog:server=localhost:514 warn;
# 调试模式(仅临时用)
error_log /var/log/nginx/debug.log debug;
# 需要 Nginx 编译时有 --with-debug
# 按条件记错误日志
map $status $loggable {
~^[23] 0;
default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;nginx -t 只能检查语法错误。运行时的问题(如连不上后端)只能从 error_log 里看。
03. 日志轮转——别让磁盘撑满
Nginx 自己不管日志轮转,日志文件会一直变大。需要用 logrotate 或操作系统的工具定期切割压缩旧日志。
logrotate 是 Linux 的标准日志管理工具——它定期把旧的日志文件重命名、压缩,并通知 Nginx 打开新日志文件(通过 USR1 信号)。
典型的配置:每天轮转、保留 30 天、压缩旧文件、延迟压缩(避免当前正在写的文件被压缩)。
注意:logrotate 执行后需要 kill -USR1 给 Nginx 发信号让它的日志指向新文件。或者用 copytruncate 模式直接截断(但可能丢几行日志)。
bash
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每天轮转一次
missingok # 日志文件不存在不报错
rotate 30 # 保留 30 份
compress # 压缩旧日志
delaycompress # 延迟压缩(留一份不压缩方便查看)
notifempty # 空文件不轮转
create 640 nginx adm # 创建新文件的权限
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}04. 条件日志与动态日志
Nginx 可以用 if 条件控制是否记录日志——健康检查、静态资源这些不需要记录的内容可以关掉日志,减少磁盘 IO 和日志量。
使用 map 指令定义一个变量,根据条件设置为 0(不记)或 1(记)。access_log 用 if= 条件引用这个变量。
还有 buffered 日志模式——Nginx 把日志先写缓冲区再批量刷盘,减少磁盘 IO 次数。buffer 和 flush 参数控制缓冲区大小和刷盘频率。
gzip 日志——日志量大时可以设置 access_log 输出通过管道传给 gzip 程序实时压缩。
nginx
# 条件日志——健康检查和静态文件不记
map $uri $loggable {
/health 0;
~* \.(css|js|png|jpg|gif)$ 0;
default 1;
}
access_log /var/log/nginx/access.log combined if=$loggable;
# 缓冲日志
access_log /var/log/nginx/access.log combined buffer=64k flush=5s;
# 压缩日志(pipe 到 gzip)
access_log /var/log/nginx/access.log.gz combined gzip buffer=64k flush=5s;缓冲日志的 flush 参数——日志在缓冲区里最多待多少秒就必须刷盘。5s 意味着最多丢最近 5 秒的日志(Nginx 挂了的话)。
05. JSON 日志与 ELK 集成
传统文本日志难以程序化分析。现在流行用 JSON 格式输出日志,直接喂给 ELK(Elasticsearch + Logstash + Kibana)或 Loki 做聚合分析。
JSON 日志定制——用 log_format 定义 JSON 格式(注意要 escape 特殊字符)。关键字段:时间戳、客户端 IP、请求 URI、状态码、响应时间、User-Agent。
配合 Filebeat 或 Fluentd 把 JSON 日志采集到 Elasticsearch。
注意:JSON 日志里别用 $http_ 开头的变量(如 Cookie)全部输出——可能泄露敏感信息。只记录需要分析的必要字段。
nginx
# JSON 格式日志
log_format json_combined escape=json '{'
'"timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"real_ip":"$http_x_forwarded_for",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"body_bytes":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_time":$upstream_response_time,'
'"user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/access.json json_combined;escape=json 是 Nginx 1.11.8 加入的参数,自动把变量里的引号反斜杠等转义成合法 JSON。不用自己手动处理了。
知识测验
第 1/5 题正确 0
access_log 和 error_log 分别记什么?