Nginx 日志管理、配置及切割
Nginx日志
Nginx日志描述
日志对于统计排错和日常服务器维护来说是非常有利的。通过访问日志,你可以得到用户地域来源、跳转来源、使用终端、某个URL访问量等相关信息;通过错误日志,你可以得到系统某个服务或server的性能瓶颈等。因此,将日志好好利用,你可以得到很多有价值的信息。
Nginx日志格式
打开nginx.conf配置文件
main 日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'$connection $upstream_addr'
'upstream_response_time $upstream_response_time request_time $request_time';
# 日志生成的到Nginx根目录/var/log/nginx/access.log文件,默认使用"main"日志格式,也可以自定义格式。
access_log /var/log/nginx/access.log main;
日志参数明细表:
字段 | 说明 |
---|---|
$remote_addr | 客户端的ip地址(代理服务器,显示代理服务ip) |
$remote_user | 用于记录远程客户端的用户名称(一般为"-") |
$time_local | 用于记录访问时间和时区 |
$request | 用于记录请求的url以及请求方法 |
$http_host | 请求地址,即浏览器中你输入的地址(IP或域名) |
$status | 响应状态码,例如:200成功、404页面找不到等 |
$body_bytes_sent | 给客户端发送的文件主体内容字节数 |
$http_user_agent | 用户所使用的代理(一般为浏览器) |
$http_x_forwarded_for | 可以记录客户端IP,通过代理服务器来记录客户端的ip地址 |
$http_referer | 可以记录用户是从哪个链接访问过来的 |
$upstream_status | upstream状态 |
$ssl_protocol | SSL协议版本 |
$ssl_cipher | 交换数据中的算法 |
$upstream_addr | 后台upstream的地址,即真正提供服务的主机地址 |
$request_time | 整个请求的总时间 |
$upstream_response_time | 请求过程中,upstream响应时间 |
Nginx日志配置
access_log /var/log/nginx/blog/blog.ansudevops.com-$logdate-access.log main;
error_log /var/log/nginx/blog/blog.ansudevops-error.log info;
open_log_file_cache max=10;
Nginx日志分隔
nginx日志分割是很常见的运维工作,从nginx 0.7.6版本开始access_log的路径配置可以包含变量,我们可以利用这个特性来实现日志分割。例如,我们想按天来分割日志,那么我们可以这样配置:
access_log logs/access-$logdate.log main;
那么接下来的问题是我们怎么提取出$logdate这个变量? 可以使用正则表达式来获取所需时间的数据。
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})")
{
set $year $1;
set $month $2;
set $day $3;
set $hour $4;
set $minutes $5;
set $seconds $6;
}
access_log logs/access-$year-$month-$day-$hour:$minutes:$seconds.log main;
也可以使用Perl语法来捕获,如下:
if ($time_iso8601 ~ "^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})") {}
access_log /data/logs/nginx/www.ttlsa.com-$year-$month-$day-access.log;
上面的方法有两个问题:一是如果if条件不成立,那么$year、$month和$month这三个变量将不会被设置,那么日志将会记录到access-$year-$month-$day.log这个文件中;二是if只能出现在server和location块中,而access_log通常会配置到顶层的http块中,这时候if就不适用。
如果要在http块中设置access_log,更好的方法是使用map指令:
map $time_iso8601 $logdate {
'~^(?<ymd>\d{4}-\d{2}-\d{2})' $ymd;
default 'date-not-found';
}
access_log logs/access-$logdate.log main;
map指令通过设置默认值,保证$logdate始终有值,并且可以出现在http块中,完美地解决了if指令的问题。
最后,为了提高日志的效率,建议配置open_log_file_cache,完整的日志分割配置如下:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
map $time_iso8601 $logdate {
'~^(?<ymd>\d{4}-\d{2}-\d{2})' $ymd;
default 'date-not-found';
}
access_log logs/access-$logdate.log main;
open_log_file_cache max=10;