4

awk处理nginx日志

 3 years ago
source link: https://blog.csdn.net/KimmKing/article/details/52727845
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

awk处理nginx日志

主要是将非结构化的日志处理成结构话数据并入库做统计,本场景是统计rest接口的调用情况:

  • nginx日志设置
  • awk抽取字段
  • awk日期格式化
  • 拼装sql与导入数据库
  • crontab自动执行
  • 配合log rotate
  • 统计分析
  • 邮件通知
  • 报表展示

nginx日志设置

nginx.conf中:

log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '$request_time $upstream_response_time $pipe'
                  '"$http_user_agent" "$http_x_forwarded_for"';
access_log  /var/log/nginx/access.log  main;
awk '{print substr($4,2,11),substr($4,14,15),substr($6,2),$7,$12,$13}'  /var/log/nginx/access.log > ~/stat.log 
# 获取访问时间,请求方法,rest url,request time和response time

日期格式化

nginx的时间是这种格式[02/Oct/2016 04:50:11],先用date格式化的方法:

awk -v A=$(date +%Y%m%d) '{gsub("/"," ",$1); sprintf("date -d \"%s %s\" \"+%%Y-%%m-%%d %%H:%%M:%%S\"", $1,$2) | getline D;printf("insert interfaceInvoke(ddate,cdate,method,url,requesttime,responsetime) values(\"%s\",\"%s\",\"%s\",\"%s\",%f,%f);\n",A,D,$3,$4,$5,$6)}' ~/stat.log > ~/stat.sql

发现经常有too many open files错误,嵌套的date命令用掉太多文件句柄,7k条测试数据执行完成需要13s。

考虑了一下,去掉gsub和date,由于时间字符串的格式是固定的、每一部分的长度也是固定的,全部使用字符串处理:

awk -v A=$(date +%Y%m%d) 'BEGIN{ mon["Jan"] = 1; mon["Feb"] = 2; mon["Mar"] = 3; mon["Apr"] = 4; mon["May"] = 5; mon["Jun"] = 6; mon["Jul"] = 7; mon["Aug"] = 8; mon["Sep"] = 9; mon["Oct"] = 10; mon["Nov"] = 11; mon["Dec"] = 12; }; {printf("insert interfaceInvoke(ddate,cdate,method,url,requesttime,responsetime) values(\"%s\",\"%s-%s-%s %s\",\"%s\",\"%s\",%f,%f);\n",A,substr($1,8,4),mon[substr($1,4,3)],substr($1,1,2),$2 ,$3,$4,$5,$6)}' ~/stat.log > ~/stat.sql

这样就不需要执行gsub替换和嵌套date命令,7k条测试执行时间只有0.026s,也可以文件句柄的问题了。

invokeStat.sh全部代码如下:

awk '{print substr($4,2,11),substr($4,14,15),substr($6,2),$7,$12,$13}' /var/log/nginx/access.log > ~/stat.log 

# insert into db
awk -v A=$(date +%Y%m%d) 'BEGIN{ mon["Jan"] = 1; mon["Feb"] = 2; mon["Mar"] = 3; mon["Apr"] = 4; mon["May"] = 5; mon["Jun"] = 6; mon["Jul"] = 7; mon["Aug"] = 8; mon["Sep"] = 9; mon["Oct"] = 10; mon["Nov"] = 11; mon["Dec"] = 12; }; {printf("insert tablename(ddate,cdate,method,url,requesttime,responsetime) values(\"%s\",\"%s-%s-%s %s\",\"%s\",\"%s\",%f,%f);\n",A,substr($1,8,4),mon[substr($1,4,3)],substr($1,1,2),$2 ,$3,$4,$5,$6)}' ~/stat.log > ~/stat.sql

mysql -h192.168.*.* -uXXX -pXXX dbname  < ~/stat.sql

crontab自动执行

/etc/crontab里,添加:

59 23 * * * root /soft/stat/invokeStat.sh
# 每天晚上12点前执行一次

配合log rotate

/etc/logrotate.d/nginx中:

/var/log/nginx/*.log {
        daily
        missingok
        rotate 52
        compress
        delaycompress
        notifempty
        create 640 nginx adm
        sharedscripts
        postrotate
                [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
        endscript
}

通过logrotate每天晚上切换一次日志,保证invokeStat.sh每天跑的都是最新的,而不是昨天的日志。其实也可以考虑这两个脚本合并成一个。invokeStat先执行。

主要先实现调用次数统计:cat file | wc -l
调用时间大于1s的统计: awk '{$13>1 {......
调用时间大于60s的统计: awk '{$13>60 {......
调用时间最长的10次统计:sort -k3nr ...... | head -n 10

crontab自动执行

/etc/crontab里,添加:

59 23 * * * root /soft/stat/invokeStat.sh
# 每天晚上12点前执行一次

先配置sendmail,然后使用mail命令:

cat ~/mystat.log | mail -s "[APP]执行时间超过1s的接口统计-"$CURDATE  [email protected]

如果发送的文件时html类型:

cat ~/mystat.log | mail -s "$(echo -e "[APP]执行时间超过1s的接口统计-$CURDATE\nContent-Type: text/html;charset=utf-8")"   [email protected]

todo list

  1. 集合echart与sql的字段组合,统计具体接口的调用情况
  2. 跟踪接口在不同时间的响应时间
  3. 优化慢请求

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK