你的Nginx服务器每天都在偷偷记录一切,只是你还不知道如何撬开它的嘴。
当你网站出现500错误时,是不是常常一头雾水地瞎猜?当遭遇恶意攻击,是不是只能后知后觉?别担心,Nginx的日志功能就像给你的服务器装上了监控摄像头,只不过你需要先学会如何调出录像。
第一部分:Nginx日志初探 - 不只是看戏的旁观者
1.1 什么是Nginx日志?
简单来说,Nginx日志就像是你的服务器写的私人日记,事无巨细地记录着每一个来访者的身份、行为和自己的内心活动(错误信息)。只不过这份日记不是用锁锁着的,而是对你完全开放的。
Nginx主要产生两种类型的日志:access_log(访问日志)和error_log(错误日志)。访问日志就像是服务器的访客登记簿,记录谁什么时候来做了什么;而错误日志则是服务器的病历本,记录它什么时候不舒服、哪里不舒服。
1.2 日志的价值比你想象的大
别小看这些枯燥的文本,它们可是宝藏。通过分析访问日志,你可以了解用户从哪里来、使用什么设备访问、哪些内容最受欢迎;通过错误日志,你可以快速定位服务器配置问题、性能瓶颈甚至安全威胁。
真正懂行的运维人员会把日志分析当作日常必修课,因为日志从不说谎,它们是最客观的见证者。
第二部分:访问日志 - 你的服务器访客登记簿
2.1 访问日志配置详解
access_log指令的语法看起来复杂,但实际上很好理解:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
举个例子,最简单的配置就是:
access_log /var/log/nginx/access.log;
这样就会使用默认的combined格式将访问日志记录到指定文件。
如果你想关闭某个层级的访问日志,可以这样:
access_log off;
2.2 自定义日志格式 - 打造你的专属日志
Nginx允许你完全自定义日志格式,就像定制你的数据收集表格一样。使用log_format指令即可:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
然后在你自定义的日志格式:
access_log /var/log/nginx/access.log main;
这样你就有了一个使用自定义格式的访问日志。
Nginx预定义了一个名为combined的日志格式,它包含了常用的日志字段:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
2.3 高级访问日志配置
对于高流量网站,每个请求都直接写入磁盘可能会影响性能。这时可以使用缓冲来优化:
access_log /var/log/nginx/access.log combined buffer=32k gzip flush=5m;
这条指令设置了32KB的缓冲区,并且启用gzip压缩(级别为1),同时如果5分钟内缓冲区未满也会强制刷新到磁盘。
注意:缓冲区大小不得超过磁盘文件原子写入的大小。
如果你的日志路径包含变量,比如按虚拟主机分开存储:
server {
root /spool/vhost/data/$host;
access_log /spool/vhost/logs/$host;
...
}
那么需要注意,缓冲写入在这种情况下不起作用。
第三部分:错误日志 - 服务器的病历本
3.1 错误日志基础配置
error_log指令的语法比access_log简单:
error_log path [level];
其中level指定日志的详细程度,可以是debug、info、notice、warn、error、crit。从左至右,日志详细程度逐级递减,即debug最详细,crit最少。
一个典型的错误日志配置:
error_log /var/log/nginx/error.log warn;
这将记录所有警告及以上级别的错误。
3.2 调试日志 - 打开Nginx的"内心世界"
有时候,你需要更详细的信息来调试问题,这时可以启用调试日志:
error_log /var/log/nginx/error.log debug;
但是,要启用调试日志,需要在构建过程中配置Nginx以支持调试:
./configure --with-debug ...
预构建的Linux软件包提供开箱即用的调试日志支持,可以使用nginx-debug二进制文件(1.9.8),可以通过以下命令运行:
service nginx stop
service nginx-debug start
Windows版本的Nginx二进制文件始终使用调试日志支持构建,因此只需设置debug级别即可。
3.3 错误日志的陷阱
一个常见的错误是:在server级别重新定义error_log而不指定级别,这会禁用调试日志:
error_log /path/to/log debug;
http {
server {
error_log /path/to/log; # 这里debug级别被去掉了!
...
为避免这种情况,要么注释掉重新定义日志的行,要么也添加debug级别规范:
error_log /path/to/log debug;
http {
server {
error_log /path/to/log debug; # 保持debug级别
...
另外,想关闭错误日志时,不要使用error_log off,这会将错误日志记录到一个名为off的文件中。正确的关闭方法是:
error_log /dev/null;
第四部分:高级日志技巧 - 从入门到精通
4.1 条件日志记录
你并不总是需要记录所有请求,比如你可能不想记录健康检查请求或者某些静态资源的请求。这时可以使用条件日志记录:
map $status $loggable {
~^[23] 0; # 2xx和3xx状态码不记录
default 1;
}
access_log /path/to/access.log combined if=$loggable;
这个例子只会记录非2xx和3xx状态的请求。
4.2 调试特定客户端IP
在生产环境调试时,你可能不想记录所有请求的调试信息,而只关注特定客户端的请求。可以使用debug_connection指令:
error_log /var/log/nginx/error.log;
events {
debug_connection 192.168.1.1;
debug_connection 192.168.10.0/24;
}
这样,只有来自指定IP或网段的连接才会生成调试日志。
4.3 内存中的日志缓冲区
在高负载情况下,即使使用文件缓冲,调试日志仍可能影响性能。这时可以使用内存缓冲区:
error_log memory:32m debug;
这样调试日志会写入一个32MB的循环内存缓冲区,即使在高负载下也不会对性能产生重大影响。
之后可以使用gdb或lldb脚本提取日志内容。
4.4 日志文件缓存
当使用变量作为日志路径时,每次写入日志都需要打开和关闭文件。为了优化性能,可以使用open_log_file_cache:
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
这个指令定义了一个缓存,用于存储包含变量的常用日志的文件描述符。参数解释:
- max:设置缓存中描述符的最大数量
- inactive:设置缓存的描述符在指定时间内没有访问则关闭
- min_uses:设置在inactive时间内文件使用的最少次数,以使描述符保持打开
- valid:设置检查文件是否仍以相同名称存在的时间
第五部分:实战示例 - 搭建完整的日志配置
5.1 综合配置示例
让我们来看一个完整的日志配置示例:
# 定义错误日志路径和级别
error_log /var/log/nginx/error.log warn;
# 定义自定义日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $bytes_sent $gzip_ratio';
log_format detailed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
# 开启日志文件缓存
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
http {
# 使用缓冲和压缩的访问日志
access_log /var/log/nginx/access.log main buffer=32k gzip flush=5m;
server {
listen 80;
server_name example.com;
# 该server使用单独的错误日志
error_log /var/log/nginx/example.com.error.log info;
# 且访问日志不记录静态资源
location /static/ {
access_log off;
...
}
# API请求使用详细日志格式
location /api/ {
access_log /var/log/nginx/api.log detailed;
...
}
}
server {
listen 80;
server_name admin.example.com;
# 管理后台记录更详细的日志
error_log /var/log/nginx/admin.example.com.error.log debug;
# 且只记录错误请求
map $status $admin_loggable {
~^[23] 0;
default 1;
}
access_log /var/log/nginx/admin.access.log main if=$admin_loggable;
}
}
5.2 日志轮转 - 不要让日志吃掉你的磁盘
随着时间推移,日志文件会越来越大,需要定期轮转。使用logrotate可以轻松管理:
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 644 nginx nginx
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
这个配置会每天轮转Nginx日志,保留52个历史版本,启用压缩,并在轮转后通知Nginx重新打开日志文件。
5.3 日志分析入门
收集了日志,如果不分析就等于白收集。这里介绍几个简单的分析方法:
- 使用awk快速分析:
# 统计HTTP状态码分布
awk '{print $9}' access.log | sort | uniq -c | sort -rn
# 找出请求最多的IP
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10
# 统计最频繁的请求URL
awk '{print $7}' access.log | sort | uniq -c | sort -rn | head -10
- 使用GoAccess实时分析:
GoAccess是一个实时的Web日志分析器:
goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED
然后你就可以通过浏览器查看漂亮的报告了。
第六部分:常见问题与解决方案
6.1 日志不记录怎么办?
- 检查Nginx配置语法:
nginx -t - 确保日志目录存在且有写权限
- 检查磁盘空间是否充足
- 查看是否在适当级别关闭了日志(比如在location中设置了access_log off)
6.2 日志文件过大怎么办?
- 配置日志轮转(如上文的logrotate配置)
- 考虑按虚拟主机分开记录日志
- 对于调试日志,只在必要时开启
- 使用gzip压缩历史日志
6.3 如何提高日志记录性能?
- 使用缓冲区(buffer参数)
- 启用压缩(gzip参数)
- 对于高流量站点,考虑将日志写入单独磁盘
- 使用内存缓冲区记录调试日志
总结:让日志成为你的得力助手
Nginx的日志功能非常强大,但很多人只使用了它的一小部分能力。通过合理配置访问日志和错误日志,你可以获得对服务器运行状态的全面洞察。
记住,好的日志配置应该:
- 记录足够的信息,但不要过多
- 结构合理,便于分析
- 性能影响最小化
- 有适当的轮转和清理策略
现在,就去检查你的Nginx日志配置吧,说不定你会发现之前忽略的重要信息。毕竟,日志就像是服务器的自我陈述,而你,应该学会倾听。
303

被折叠的 条评论
为什么被折叠?



