在系统调优的时候,经常要去分析nginx的请求日志,统计、分析各个时间段的请求量。当然分析nginx日志的方法很多,本文使用awk技术分析日志。
awk是什么
awk是一个强大的文本分析工具,awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本操作。
之所以叫awk是因为其取了三位创始人Alfred Aho、Peter Weinberger和Barian Kernighan的Family Name的首字母。
在 20 世纪 80 年代中期,对 AWK 语言进行了更新,并不同程度地使用一种称为 NAWK (New AWK) 的增强版本对其进行了替换。许多系统中仍然存在着旧的 AWK 解释器,但通常将其安装为 oawk (Old AWK) 命令,而 NAWK 解释器则安装为主要的 awk 命令,也可以使用 nawk 命令。Dr. Kernighan 仍然在对 NAWK 进行维护,与 GAWK 一样,它也是开放源代码的,并且可以免费获得(请参见参考资料部分)。
GAWK 是 GNUProject 的 AWK 解释器的开放源代码实现。尽管早期的GAWK 发行版是旧的 AWK 的替代程序,但不断地对其进行了更新,以包含 NAWK 的特性。
一般的,AWK 始终表示引用通用的语言,而 GAWK 或 NAWK 实现所特有的特性则使用它们的名称进行引用。
基本概念
NR(Number of Record,记录数,awk中默认一行为一个记录)
NF ( Number of Fileds )是指awk正在处理的记录包含几个域(字段),这于域分隔符有关,默认为空
$0 为获取全部的列
$N 为第N列
语法
awk -F ‘文本切割符’‘{处理过程}’ 文件名称
awk、sed、grep比较
grep 更适合单纯的查找或匹配文本
sed 更适合编辑匹配到的文本
awk 更适合格式化文本,对文本进行较复杂格式处理
常见的nginx日志格式
log_format main '$http_x_forwarded_for - $remote_user [$time_iso8601] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $remote_addr $request_time $http_host ';
49.4.16.120 - - [2019-07-24T11:32:05+08:00] "GET /dict.do?from=huohou&appkey=sowOTUsbfI&type=62&dataType=json&title=好好学习 HTTP/1.1" 200 154 "-" "Vert.x-WebClient/3.5.4" 192.168.1.7 0.014 api.hudong.com
// 打印第一列
cat access.log | awk '{print $1}'
// 打印所有列
cat access.log | awk '{print $0}'
// 打印奇数行
awk -F " " ' NR%2==1{print $0}' access.log
cat access.log | awk 'NR==2 {print $3}'
// 包含dict请求,相应时间小于0.112s
cat access.log | awk -F " " ' {if(match($0,"dict")&&($(NF-1) < 0.112)){print NR,$0}}'
//或者
cat access.log | awk -F " " ' match($0,"dict")&&($(NF-1) < 0.112){print NR,$0}'
cat access.log | awk -F " " ' match($0,"dict")&&($(NF-1) < 0.112)&&NR<5{print NR,$0}'
cat access.log | awk -F " " ' NR<5&&match($0,"dict")&&($(NF-1) < 0.112){print NR,$0}'
cat access.log | awk '(NR>=5&&NR<=10){print NR,$0}'
//或者
cat access.log | awk 'NR==5,NR==10{print NR,$0}'
cat access.log |awk -F " " 'NR==2 {for (i=1;i<=NF;i++)printf("%s%s%s ", i,"======",$i);print ""}'
//或者使用print函数,会换行
cat access.log |awk -F " " 'NR==12 {for (i=1;i<=NF;i++)print( i "======" $i)}'
awk '{printf "|%-30s|\n",$1}' access.log
//30个格、向左对齐的字符串
awk 'NR==3{printf "|%30s|\n",$1}' access.log
cat access.log | awk -F " " '$(NF-1) > 2 && $(NF-1) <4{print $(NF-1) "\t" "===============" $0}'
awk 'END{print NR}' access.log
//
awk ' BEGIN { print "统计";total=0} {total=total+1}END {printf "总计:%.2f",total}' access.log
awk ' BEGIN { print "统计";total=0} {total=total+1}END {printf "总计:%.2f",total}' access.log
awk -F " " 'BEGIN{} { for (i=NF;i>0;i--){if(i!=1){printf("%s%s",$i,FS)}else{printf("%s",$i)} }}' access.log
grep '2019-07-24T00:00' access.log | wc -l
//或者
grep '2019-07-24T00:00' access.log | awk -F “” 'END{print NR}'
注:wc -l
统计输出信息的行数。更准确的来说,wc -l原本就不是用来查看行数的,而是用来查看文件的newline的数量的。
11. 排序
awk -F " " 'NR==1,NR==20{print $4}' access.log |sort
//从大到小
awk -F " " 'NR==1,NR==20{print $4}' access.log |sort -r
//或者
awk -F " " 'NR==1,NR==20{print $4, $16 | "sort -r"}' access.log
//按照第二列排序
awk -F " " 'NR==1,NR==20{print $4, $16 | "sort -r -k2"}' access.log
//统计ip 并排序
awk -F " " 'NR==1,NR==200{print $4, $1 | "sort -r -k2"}' access.log
awk '{sum[$1]++}END{for(ip in sum) print ip, sum[ip]}' access.log
awk '{sum[$1]++}END{for(ip in sum) print ip, sum[ip]}' access.log | sort -rn -k2|head
注:
-r 逆序,从大到小,-n 已数值作比较,可以连写为-rn;
head 命令表示选取文本的前x行。通过head -5 就可以得到排序结果中前五行的内容。
默认输出文件前10行
awk '{sum[$1]++}END{for(ip in sum){if(sum[ip]>2000) print ip, sum[ip]} }' access.log | sort -rn -k2|head
//等价于
awk '{print $1}' access.log|sort | uniq -c |sort -n -k 1 -r|head
注:
uniq 命令用来过滤重复部分显示文件内容,这个命令读取输入文件,并比较相邻的行
常用: uniq -c 首行显示文件中出现的次数
awk '{split($4,a,":");b[a[1]]+=1} END{for(i in b) printf("%10s %5d\n",i,b[i])}'
awk '{gsub( "T"," ",$4),split($4,a,":");b[a[1]]+=1} END{for(i in b) printf("%10s %5d\n",i,b[i])}'
awk '{split($4,a,":");b[a[1]]+=1} END{for(i in b) printf("%10s %5d\n",i,b[i])}' access.log
$ awk -f functions.awk
//新建一个functions.awk文件,内容为:
function addition(num1, num2)
{
result = num1 + num2
return result
}
BEGIN {
res = addition(10, 20)
print "10 + 20 = " res
}