Author: haoransun
Wechat: SHR—97
学习来源:极客时间-Nginx核心知识100讲,本人购买课程后依据视频讲解汇总成个人见解。
前言
通过访问日志,可以知晓用户的地址,网站的哪些部分最受欢迎。用户的浏览时间,对大多数用户的浏览器做出针对性优化。
Nginx会把每个用户访问的日志信息记录到指定的日志文件里,供网站管理员分析用户浏览行为等,此功能又ngx_http_log_module 模块负责。
1 访问日志参数
Nginx访问日志主要有两个参数控制
- log_format:用来定义记录日志的格式(可以定义多种日志格式,取不同名字即可)。
- access_log:用来指定日至文件的路径及使用的何种日志格式记录日志。
1.1 log_format与 access_log的默认值
1 | access_log logs/access.log main; |
logs/access.log:这个为日志文件的存放路径,从安装目录开始,意思绝对路径为:/home/geek/nginx/logs/access.log
main:日志格式,通常为 combined
若不想记录Nginx的日志:access_log off;
1.2 log_format语法格式及参数语法说明
1 | log_format <NAME> <String>; |
1.3 x_forwarded_for
通常web服务器放在反向代理的后面,这样就不能获取到客户的IP地址了,通过$remote_addr拿到的IP地址是反向代理服务器的iP地址。反向代理服务器在转发请求的http头信息中,可以增加x_forwarded_for信息,用以记录原有客户端的IP地址和原来客户端请求的服务器地址。
注意:
在定义日志目录中要注意的是,nginx进程设置的用户和组必须有对该路径创建文件的权限,
假设nginx的usr指令设置的用户名 和用户组都是www,而logs 目录的用户名和组是root,那么日志文件将无法被创建。
用nginx做前端代理后,我们发HTTP_X_FORWARDED_FOR 无法获取到客户端真实的IP地址了。
原因 nginx 默认并不会增加 X_FORWARDED_FOR 头信息,我们给他加上就好了。简单配置如下:
1 | location / { |
重启nginx 加载新的配置文件,就可以获取客户端真实的IP地址了。
通常情况下用以上配置即可,可以将main换成combined(默认的日志格式),其他不变即可。
1.4 access_log语法格式及参数语法说明
1 | access_log <FILE> <NAME>; |
一般场景这些参数都无需配置,极端优化才有可能会
考虑这些参数。
1.5 设置刷盘策略:
1 | access_log /home/geek/nginx/logs/access.log buffer=32k flush=5s; |
buffer 满32k才刷盘;假如buffer不满5s强制刷盘。
1.6 其他:
error_log:配置错误日志,例如上例。
open_log_file_cache:
对于每一条日志记录,都将是先打开文件,再写入日志,然后关闭。可以使用open_log_file_cache来设置日志文件缓存(默认是off)。语法:
open_log_file_cache max=N [inactive= time] [min_uses=N] [valid= time];
参数注释如下:
- max:设置缓存中的最大文件描述符数量,如果缓存被占满,采用LRU算法将描述符关闭。
- inactive:设置存活时间,默认是10s
- min_uses:设置在inactive时间段内,日志文件最少使用多少次后,该日志文件描述符记入缓存中,默认是1次
- valid:设置检查频率,默认60s
- open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
2 日志分析:
通过对日志格式的定义,就可以使用常见的 Linux 命令行工具进行分析了:
查找访问频率最高的 URL 和次数:
1 | cat access.log | awk -F ‘^A’ ‘{ print $10}’ | sort | uniq -c |
查找当前日志文件 500 错误的访问:
1 | cat access.log | awk -F ‘^A’ ‘{ if( $5 == 500) print $0}’ |
查找当前日志文件 500 错误的数量:
1 | cat access.log | awk -F ‘^A’ ‘{ if( $5 == 500) print $0}’ | wc -l |
查找某一分钟内 500 错误访问的数量:
1 | cat access.log | awk -F ‘^A’ ‘{ if( $5 == 500) print $0}’ | grep ’09:00’ | wc -l |
查找耗时超过 1s 的慢请求
1 | tail -f access.log | awk -F ‘^A’ ‘{ if( $6>1) print $0}’ |
3 日志切割
为了使Nginx的日志文件存储更合理、有序,我们需要将日志文件进行分开存储。
可以按时间来分开存储。今天的日志文件存储到一个文件中,明天的日志文件则存储到另一个新的文件中等等。
有两种方式:
- 1 手动切割
(1)进入 logs目录,执行命令即将以前的日志文件重命名为一个新的名字的日志文件。1
mv access.log xxx(随便起个名).log
(2)执行命令kill -USR1 主进程号 :1
kill -USR1 主进程号(需要先用 ps -ef| grep nginx命令找到master的进程号)
在logs目录ls一个,会发现又自动多出了一个日志文件(这个日志文件的命名来源于nginx.conf文件里的access_log的路径),并且里面无内容。这个文件就是切割出来的新文件,再有日志会往这里面写,而不会操作老日志文件。
- 2 自动进行切割
(1)首先创建个sh文件(称为批处理日志文件),进入nginx的logs目录运行命令(2)编辑cutlog.sh文件。输入如下内容:1
touch cutlog.sh(文件名自定义,后缀.sh即可)
1 | vim cutlog.sh |
说明:
D=$(date +%Y%m%d),声明个变量,名为D(自定义),值为date(Linux自带的,类似于函数,用于获取当前时间,并且格式为年月日)
${D}:引用上面变量名为D的变量
$(cat /usr/local/nginx/nginx.pid):cat命令意思是查看。nginx.pid:存储的是nginx的主进程号。连起来的意思就是查看nginx主进程号,带上$(xx)就是说拿到xx
(3)定时执行某个文件,输入如下命令:(注意:运行crontab命令需要先用yum进行安装crontab,否则会出现command not found)
1 | crontab -e |
(4)执行完(3)后会出现编辑器,输入如下内容:
1 | 23 59 *** /bin/bash /usr/local/nginx/logs/cutlog.sh |
即:在每天23点59分定时执行cutlog.sh文件,这样就实现了每天定时切割日志文件了。
原理:只是将手动切割写成个脚本。
如有需要每隔1个月就备份日志到其他地方并删除原位置的日志等类似需求都可以写个shell脚本,然后用linux的crontab来定时执行。
4 实例
往往需要要对access_log、error_log日志进行切割。切割日志一般利用USR1信号让nginx产生新的日志
1 | #!/bin/bashlogdir="/data/logs/nginx" pid=`cat $logdir/nginx.pid` DATE=`date -d "1 hours ago" +%Y%m%d%H` DATE_OLD=`date -d "7 days ago" +%Y%m%d` for i in `ls $logdir/*access.log`; do mv $i $i. $DATE done for i in `ls $logdir/*error.log`; do mv $i $i. $DATE done kill -s USR1 $pid rm -v $logdir "/access.log." $DATE_OLD*rm -v $logdir"/error.log." $DATE_OLD* |
1、分析:将上面的脚本放到crontab中,每小时执行一次(0 ),这样每小时会把当前日志重命名成一个新文件;然后发送USR1这个信号让Nginx 重新生成一个新的日志。(相当于备份日志)将前7天的日志删除;
2、说明:在没有执行kill -USR1 $pid之前,即便已经对文件执行了mv命令而改变了文件名称,nginx还是会向新命名的文件”*access.log.2016032623”照常写入日志数据的。原因在于:linux系统中,内核是根据文件描述符来找文件的。
3、logrotates:使用系统自带的logrotates,也可以实现nginx的日志分割,查看其bash源码,发现也是发送USR1这个信号。