5月27日 22:13

Nginx 日志怎么配置?有哪些格式和优化方法?

Nginx 如何配置日志?有哪些日志格式和优化方法?

Nginx 提供了访问日志(access_log)和错误日志(error_log)两种日志类型。面试中常考的是日志格式自定义、条件记录和性能优化三条主线。

访问日志与自定义格式

访问日志通过 log_format 定义格式,再用 access_log 引用。常用三种格式:

  • main 格式:记录 IP、请求行、状态码、Referer、UA、耗时等基础信息
  • detailed 格式:在 main 基础上增加 upstream 地址、状态、X-Forwarded-For、request_id
  • JSON 格式:用 escape=json 转义,方便 ELK/Grafana Loki 等工具直接解析
nginx
log_format main "$remote_addr - $remote_user [$time_local] " ""$request" $status $body_bytes_sent " ""$http_referer" "$http_user_agent" " "$request_time $upstream_response_time"; log_format json_combined escape=json "{" ""time_local":"$time_local", ""remote_addr":"$remote_addr", ""request":"$request", ""status":"$status", ""request_time":"$request_time"" "}"; access_log /var/log/nginx/access.log main;

追问:access_log 和 error_log 有什么区别? access_log 记录每次请求的详细信息,可自定义格式;error_log 记录服务器错误,不支持自定义格式,只能设级别(debug/info/notice/warn/error/crit/alert/emerg)。

日志性能优化

高并发场景下日志写入会成为瓶颈,核心优化手段:

  • 关闭不必要的日志:静态资源、健康检查路径用 access_log off
  • 缓冲写入access_log ... buffer=32k flush=5s,减少磁盘 I/O 次数
  • gzip 压缩access_log ... gzip=9,节省磁盘空间
  • 条件记录:用 map + if= 只记录特定状态码或慢请求
nginx
map $status $loggable { ~^[23] 0; default 1; } access_log /var/log/nginx/access.log main if=$loggable; location ~* \.(css|js|jpg|png|gif|ico)$ { access_log off; } access_log /var/log/nginx/access.log main buffer=32k flush=5s;

追问:buffer 和 flush 参数分别控制什么? buffer 控制缓冲区大小,写满才刷盘;flush 控制最大等待时间,超时强制刷盘。两者配合保证日志既不丢又不多写。

日志轮转与分离

单文件日志会无限增长,必须配合 logrotate 轮转:

bash
# /etc/logrotate.d/nginx /var/log/nginx/*.log { daily rotate 14 compress delaycompress missingok sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid) endscript }

kill -USR1 让 Nginx 重新打开日志文件,不会中断服务。

按业务分离日志同样重要:API 请求写独立文件,不同 server 块各写各的,便于精准排查问题。

常用变量速查

变量说明
$remote_addr客户端 IP
$status响应状态码
$request_time请求总耗时
$upstream_response_time上游响应时间
$http_x_forwarded_for真实客户端 IP

生产环境建议用 JSON 格式 + 缓冲写入 + logrotate 轮转 + 条件过滤,四板斧组合基本够用。

标签:Nginx