Nginx运维篇——Nginx的日志介绍
前言
本篇文章将对nginx服务中提供的日志文件进行介绍,同时对我们日常运维中对nginx日志常见的操作进行分享
一、Nignx的日志类型
我们进入到nginx
目录下的log
目录中,可以看到里面存放着三个文件,分别是access.log
,error.log
和nginx.pid
文件,其中nginx.pid
是用来记录当前nginx进程的pid号的,不属于日志文件。真正属于日志文件的是另外两个文件。
-rw-r--r-- 1 root root 90261926 Jun 9 09:38 access.log
-rw-r--r-- 1 root root 21159964 Jun 8 16:36 error.log
-rw-r--r-- 1 root root 5 May 24 15:18 nginx.pid
(一)access.log日志文件
1、access.log文件的介绍
access文件用于存放每个用户访问网站的请求日志,开发运维人员通过访问日志来分析用户的浏览器行为。默认情况下,nginx会在log
目录下生成该文件,无需用户配置。
2、access.log
的相关配置
我们可以在$nginx_home/conf/nginx.conf
配置文件中对nginx请求日志进行配置。配置的格式为:
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
其中,access_log
是关键字,表示接下来的配置是关于access日志的配置,path
为该日志文件的存储路径,后面还可以对日志输出格式、是否压缩、日志刷新时间等设置进行配置。可能有读者会留意到,上面截图中的用例在path
后面写上了main
,其实这里的main
并不是什么关键字,而是nginx默认定义好的一个日志格式名称,我们可以在log_format
中看到,nginx默认定义了一个名为main
的日志输出格式。
- 关于日志输出格式的配置
nginx自带了一些变量,让我们能够作为日志输出格式进行配置,方便我们对用户的请求进行查询和统计。当然了,nginx其实默认的日志输出格式其实就已经把一些重要的请求参数保存到访问日志里面了,基本满足我们日常使用了,如果有需要可以根据下面的表单自定义配置所需要的日志格式。
参数 | 说明 | 示例 |
---|---|---|
$remote_addr | 客户端地址 | 211.28.65.253 |
$remote_user | 客户端用户名称 | -- |
$time_local | 访问时间和时区 | 18/Jul/2012:17:00:01 +0800 |
$request | 请求的URI和HTTP协议 | "GET /article-10000.html HTTP/1.1" |
$http_host | 请求地址,即浏览器中你输入的地址(IP或域名) | www.wang.com 192.168.100.100 |
$status | HTTP请求状态 | 200 |
$upstream_status | upstream状态 | 200 |
$body_bytes_sent | 发送给客户端文件内容大小 | 1547 |
$http_referer | url跳转来源 | https://www.baidu.com/ |
$http_user_agent | 用户终端浏览器等信息 | "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; SV1; GTB7.0; .NET4.0C; |
$ssl_protocol | SSL协议版本 | TLSv1 |
$ssl_cipher | 交换数据中的算法 | RC4-SHA |
$upstream_addr | 后台upstream的地址,即真正提供服务的主机地址 | 10.10.10.100:80 |
$request_time | 整个请求的总时间 | 0.205 |
$upstream_response_time | 请求过程中,upstream响应时间 | 0.002 |
下面我们来简单地自定义一个日志输出格式,并且应用起来。
步骤一:在http标签下新增一个log_format
格式
步骤二:在server标签中应用定义新的access_log
配置
server {
listen 9600;
location / {
root html;
access_log logs/mine_access.log mine_format;
}
}
步骤三:使用nginx -s reload
重新加载配置文件
(注意,如果这里提示说日志文件不存在的话,就自己先手动建一下文件即可)
自己手动访问几次服务,就可以看到新生成的日志格式会和我们定义的日志格式一致了。
- 关于刷新时间的配置
nginx默认情况下对访问日志是实时记录的,其实一定程度上来说是会占用cpu资源的,当然了大部分站点其实访问量并不大,所以实时记录日志所带来的性能消耗是可以忽略的。如果说对于访问量大且对性能要求较高的站点,可能会希望通过优化日志的输出频率来达到减少IO的效果。
location / {
root html;
access_log logs/mine_access.gz mine_format gzip flush=5s;
}
我们可以看一下官方对这个配置的介绍
配置完flush和buffer
后,其实我们就相当于是有两个记录日志的节点了,一个是缓冲区满了,另外一个是到刷新日志的时间点了。缓冲区的存在使得nginx不需要针对每一个请求都做一次IO,可以节省一点系统资源。当然了,我们还可以开启gzip压缩(可选等级为1-9,级别越高压缩级别越高)来进一步减轻磁盘压力。
- 关闭访问日志的记录
只需要配置access_log
为off
即可
location / {
root html;
access_log off;
}
(二)error.log错误日志
相比于访问日志来说,运维人员可能更加关注错误日志文件,错误日志文件记录了nginx运行过程中遇到的错误信息(注意,也包括用户请求没有正常响应的错误日志),向有时候我们nginx启动失败后,都可以在这个error日志中找到对应较为详情的报错信息。
这里贴一下官网对error.log
的介绍,该错误日志的配置格式为:error_log path level
,error_log为关键字,path为日志保存的路径,level为日志级别。默认情况下nginx会在logs目录下建立一个名为error.log
的日志文件,且日志级别为error。可选的日志级别配置从低到高分别为debug, info, notice, warn, error, crit, alert, emerg。
我们可以简单演示一下,这个错误日志的用法
server {
listen 9600;
location / {
root html;
access_log logs/mine_access.log mine_format;
error_log logs/mine_error.log warn;
}
}
配置完后reload一下nginx配置,然后在浏览器中随意访问一下不存在的资源,我们就可以在日志文件里面看到相关的错误日志了。
二、运维优化
(一)实现日志按指定时间分割处理
nginx默认是不会进行日志文件的分割操作的,也就是所有访问日志会一直往access.log
文件里面追加,时间一长的话这个文件就会变得很大,而且运维人员在查看当天文件的也很不方便。所以一般来说,我们都会选择按日对日志文件进行切割。
常见的处理方案有2种:(1)直接在nginx配置文件中配置(2)通过linux的crontab
配置定时任务,自己手动写一下定时处理的脚本。下面我们就来讲讲这两种处理方案:
方案一:在nginx配置文件中配置
在Nginx配置文件中,可以使用$time_local
或$time_iso8601
变量来获取当前时间,然后将其作为日志文件名的一部分。所以我们可以这样配置我们的日志文件名。
步骤一:在http标签块中按照我们需要的日期格式yyyy-MM-dd
定义变量$logdate
http {
...
map $time_iso8601 $logdate {
'~^(?<ymd>\d{4}-\d{2}-\d{2})' $ymd;
default 'date-not-found';
}
...
}
步骤二:在对应的站点中使用变量来动态生成日志文件
location / {
root html;
access_log /opt/nginx/logs/mine_access.$logdate.log mine_format;
error_log /opt/nginx/logs/mine_error.log warn;
}
这里需要注意的是,error_log
日志文件可能会由于nginx版本的原因,无法使用变量来动态切割每天的日志,所以感觉这种方法并不完全适用。
步骤三:重新加载一下配置文件,上述配置即可生效了
方案二:结合crontab定时任务来完成日志的切割效果(更推荐)
步骤一:写一下按日切割文件的日志脚本,命名为nginx_log_split.sh
简单解释一下脚本做的工作,根据年/月
生成对应的目录,然后把日志文件重命名后放入到对应月份的目录中,最后再通过nginx -s reopen
命令重新启动日志。
吐槽一下,本来是想用current_date
作为变量名的,但似乎触发了简书的bug,一直保存不了....
#!/bin/bash
nginx_home=/opt/nginx/
nginx_log_path=${nginx_home}logs/
current_date1=$(date +%Y-%m-%d)
access_log_file_name=access.log
error_log_file_name=error.log
history_file_path=${nginx_home}logs/history_log/$(date +%Y)/$(date +%m)
# check if the nginx server alive
if [ -e ${nginx_log_path}nginx.pid ];then
# create log folder for nginx log file
if [ ! -e ${history_file_path} ];then
mkdir -p ${history_file_path}
echo "$(date) create folder success"
fi
# rename the log file with current date
if [ -e $nginx_log_path$access_log_file_name ];then
mv ${nginx_log_path}${access_log_file_name} ${history_file_path}/access-${current_date1}.log
echo "$(date) rename access.log successfully"
else
echo "$(date) access.log file no exist,skip"
fi
if [ -e $nginx_log_path$error_log_file_name ];then
mv ${nginx_log_path}${error_log_file_name} ${history_file_path}/error-${current_date1}.log
echo "$(date) rename error.log successfully"
else
echo "$(date) error.log file no exist,skip"
fi
# reopen the nginx server log
${nginx_home}/sbin/nginx -s reopen
echo "$(date) reload log file success"
else
echo "$(date) nginx server is close,skip"
fi
步骤二:给脚本授权
chmod 774 nginx_log_split.sh
步骤三:配置crontab定时器
通过crontab定时器,让系统每天晚上23:59
分的时候跑一次我们的脚本,生成分割当天的日志文件。然后顺便把执行日志输出到指定的文件中,方便我们查看。
59 23 * * * /opt/nginx/logs/nginx_split_log.sh > /opt/nginx/logs/history_log/execute.log 2>&1
为什么说个人更推荐这种写法呢?我感觉通过定时任务来做的话,灵活性更强,我们可以根据自己的需要来决定怎么分割日志文件,另外更方便管理,通过脚本我们可以更好的管理我们的日志文件(像上面的脚本,我们就可以通过年/月的格式来存放我们的日志文件,一目了然)。
(二)按模块区分访问日志
对于站点较多,且都部署在同一台nginx服务器(或者同一个nginx集群)的企业,一般我们会习惯性的将不同站点的日志分开管理,避免所有的站点日志都输出在同一个access.log
文件中,导致后续统计或者排查问题的时候容易混淆。
server {
listen 9600;
location / {
root html;
access_log /opt/nginx/logs/mine_access1.log mine_format;
error_log /opt/nginx/logs/mine_error.log warn;
}
}
server {
listen 9601;
location / {
root html;
access_log /opt/nginx/logs/mine_access2.log mine_format;
}
}
参考文章:
nginx官网:http://nginx.org/en/docs/http/ngx_http_log_module.html#log_format