Nginx 如何配置日志?有哪些日志格式和优化方法?
Nginx 日志对于监控、调试和安全审计非常重要。合理配置日志可以帮助快速定位问题和优化性能。
访问日志配置:
nginxhttp { # 自定义日志格式 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 detailed '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time ' '$upstream_addr $upstream_status ' '$http_x_forwarded_for $request_id'; # JSON 格式日志 log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status":"$status",' '"body_bytes_sent":"$body_bytes_sent",' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent"' '}'; # 应用日志格式 access_log /var/log/nginx/access.log main; server { listen 80; server_name example.com; # 使用不同的日志格式 access_log /var/log/nginx/example.com.access.log detailed; location / { proxy_pass http://backend; } } }
错误日志配置:
nginx# 错误日志级别:debug, info, notice, warn, error, crit, alert, emerg error_log /var/log/nginx/error.log warn; # 不同级别的错误日志 error_log /var/log/nginx/error.log info; error_log /var/log/nginx/crit.log crit;
日志优化:
nginxhttp { # 禁用特定路径的日志 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; } # 禁用健康检查日志 location /health { access_log off; return 200 "OK"; } # 缓冲日志写入 access_log /var/log/nginx/access.log main buffer=32k flush=5s; # 压缩日志 access_log /var/log/nginx/access.log main gzip=9; }
条件日志记录:
nginxhttp { # 根据状态码记录日志 map $status $loggable { ~^[23] 0; default 1; } # 根据请求方法记录日志 map $request_method $loggable_method { GET 1; POST 1; default 0; } server { listen 80; server_name example.com; # 只记录特定状态码的请求 access_log /var/log/nginx/access.log main if=$loggable; # 只记录特定方法的请求 access_log /var/log/nginx/method.log main if=$loggable_method; location / { proxy_pass http://backend; } } }
分离日志:
nginxhttp { # API 日志 log_format api '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time"'; server { listen 80; server_name example.com; # 主站点日志 access_log /var/log/nginx/main.log main; # API 日志 location /api/ { access_log /var/log/nginx/api.log api; proxy_pass http://api_backend; } # 静态资源不记录 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; root /var/www/static; } } }
日志轮转:
bash# /etc/logrotate.d/nginx /var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 nginx adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript }
日志分析变量:
nginxlog_format analysis '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time ' '$upstream_addr $upstream_status ' '$scheme $server_name $request_uri ' '$http_host $http_x_forwarded_for ' '$request_id $connection $connections ' '$time_iso8601 $msec';
常用日志变量:
| 变量 | 说明 |
|---|---|
| $remote_addr | 客户端 IP 地址 |
| $remote_user | 认证用户名 |
| $time_local | 本地时间 |
| $request | 完整的请求行 |
| $status | 响应状态码 |
| $body_bytes_sent | 发送的字节数 |
| $http_referer | 来源页面 |
| $http_user_agent | 用户代理 |
| $request_time | 请求处理时间 |
| $upstream_response_time | 上游响应时间 |
| $upstream_addr | 上游服务器地址 |
| $upstream_status | 上游状态码 |
| $request_id | 请求 ID |
| $http_x_forwarded_for | 真实客户端 IP |
日志监控和告警:
nginx# 自定义错误日志格式 log_format error_log_format '$time_local [$level] $message'; # 记录慢请求 log_format slow_request '$remote_addr - $remote_user [$time_local] ' '"$request" $status $request_time ' 'upstream_response_time=$upstream_response_time'; http { # 慢请求阈值 map $request_time $slow_request { default 0; ~^([1-9]\d*\.?\d*|0\.\d*[1-9]\d*) 1; } server { listen 80; server_name example.com; # 记录慢请求 access_log /var/log/nginx/slow.log slow_request if=$slow_request; location / { proxy_pass http://backend; } } }
日志安全:
nginxhttp { # 不记录敏感信息 log_format secure '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time'; server { listen 80; server_name example.com; # 不记录密码等敏感信息 location /login { access_log /var/log/nginx/login.log secure; proxy_pass http://auth_backend; } # 不记录敏感路径 location ~* ^/(admin|api/v1/users) { access_log /var/log/nginx/sensitive.log secure; proxy_pass http://backend; } } }
完整日志配置示例:
nginxuser nginx; worker_processes auto; http { # 日志格式 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 api '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time" ' 'upstream_addr=$upstream_addr upstream_status=$upstream_status'; log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status":"$status",' '"body_bytes_sent":"$body_bytes_sent",' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent",' '"upstream_response_time":"$upstream_response_time"' '}'; # 全局日志 access_log /var/log/nginx/access.log main buffer=32k flush=5s; error_log /var/log/nginx/error.log warn; # 条件日志 map $status $loggable { ~^[23] 0; default 1; } # 慢请求 map $request_time $slow_request { default 0; ~^([1-9]\d*\.?\d*|0\.\d*[1-9]\d*) 1; } server { listen 80; server_name example.com; # 主日志 access_log /var/log/nginx/example.com.access.log main if=$loggable; # 慢请求日志 access_log /var/log/nginx/slow.log main if=$slow_request; # API 日志 location /api/ { access_log /var/log/nginx/api.log api; proxy_pass http://api_backend; } # 静态资源不记录 location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; root /var/www/static; } # 健康检查不记录 location /health { access_log off; return 200 "OK"; } location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } }
日志分析工具:
- GoAccess:实时日志分析
- AWStats:Web 日志分析
- ELK Stack:Elasticsearch + Logstash + Kibana
- Grafana + Loki:日志监控和可视化
- Splunk:企业级日志分析
日志优化建议:
- 合理设置日志级别:生产环境使用 warn 或 error
- 使用缓冲:减少磁盘 I/O
- 定期轮转:避免日志文件过大
- 压缩旧日志:节省磁盘空间
- 分离日志:按业务类型分离
- 条件记录:只记录必要的信息
- 使用 JSON 格式:便于机器解析
- 监控日志大小:防止磁盘占满