Nginx 访问日志与日志格式
1. 先理解这件事
对新手来说,可以先把访问日志理解成一句话:
- 它记录了“谁在什么时间访问了什么资源,结果怎么样”
访问日志最直接的用途有三个:
- 确认请求是否真的到达了 Nginx
- 观察状态码、响应时间和请求来源
- 为后续分析流量、排查问题、做告警提供原始数据
对有经验的读者,更值得关注的是:
- 日志字段是否足够支持排障和性能分析
- 日志格式是否方便被 ELK、Loki、Datadog 等系统采集
- 高流量场景下日志 I/O 是否成为额外负担
2. 最小可用配置
http {
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;
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
}先看懂这几行:
log_format main ...定义一套可复用的日志格式access_log /var/log/nginx/access.log main;表示把访问日志写到指定文件,并套用mainrequest_time、upstream_response_time这些字段可以帮助判断慢请求发生在 Nginx 还是上游服务
3. 常见字段怎么理解
最常用字段包括:
$remote_addr:客户端来源 IP$time_local:本地时间格式的请求时间$request:原始请求行,通常包含方法、路径和协议版本$status:响应状态码$body_bytes_sent:返回给客户端的响应体大小$http_referer:来源页面$http_user_agent:客户端标识$request_time:Nginx 处理完整个请求所花时间$upstream_response_time:上游服务实际处理时间
新手先把下面三类字段用起来就够了:
- 访问来源
- 状态码
- 耗时
进阶再补:
- 上游连接耗时
- 上游响应耗时
- 转发目标标识
4. 一套更适合排障的日志格式
http {
log_format upstream_timing '$remote_addr [$time_local] '
'"$request" $status $body_bytes_sent '
'host=$host uri="$uri" args="$args" '
'rt=$request_time '
'uaddr=$upstream_addr '
'ustatus=$upstream_status '
'uct=$upstream_connect_time '
'uht=$upstream_header_time '
'urt=$upstream_response_time';
access_log /var/log/nginx/access.log upstream_timing;
}这套格式的价值在于:
- 能分辨慢请求到底慢在客户端传输、Nginx 本身还是上游服务
- 能看见请求最终被转发到了哪个上游地址
- 能为后续做性能优化和故障定位留足上下文
5. 配置时的实践建议
- 日志格式先满足排障,再考虑精简。
- 字段命名尽量稳定,避免后续日志平台解析规则反复调整。
- 高并发场景要评估日志量,必要时配合日志切分和采集系统使用。
- 对健康检查、静态资源等高频低价值请求,可以考虑单独日志策略。
6. 常见误区
6.1 只记录默认格式,后面排障信息不够
这是最常见的问题。
默认格式能看基础状态,但很多线上问题真正需要的是:
- 请求耗时
- 上游耗时
- 上游状态
- 具体转发目标
6.2 字段加得太多,日志量暴涨
日志不是字段越多越好,而是要围绕分析目标设计。
更合理的做法是:
- 核心访问日志保留稳定字段
- 特殊场景单独定义更详细的格式
7. 排查清单
-
access_log已明确写到预期位置 -
log_format命名清晰且已被实际引用 - 已记录状态码、请求耗时、上游耗时等关键字段
- 日志目录权限正确,Nginx 可正常写入
- 已配合日志切分或采集方案,避免单文件无限增长