利用shell命令统计日志的方法详解
前言
大家都知道,通过使用shell命令可以很方便地对日志进行统计和分析,当服务有异常的时候,需要去排查日志,那么掌握一种统计日志的技巧就是必不可少的了。
假设有一个包含下面内容的日志文件access.log。我们以统计这个文件的日志为例。
date=2017-09-2313:32:50|ip=40.80.31.153|method=GET|url=/api/foo/bar?params=something|status=200|time=9.703|bytes=129|referrer="-"|user-agent="Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/535.7(KHTML,likeGecko)Chrome/16.0.912.63Safari/535.7"|cookie="-" date=2017-09-2300:00:00|ip=100.109.222.3|method=HEAD|url=/api/foo/healthcheck|status=200|time=0.337|bytes=10|referrer="-"|user-agent="-"|cookie="-" date=2017-09-2313:32:50|ip=40.80.31.153|method=GET|url=/api/foo/bar?params=anything|status=200|time=8.829|bytes=466|referrer="-"|user-agent="GuzzleHttp/6.2.0curl/7.19.7PHP/7.0.15"|cookie="-" date=2017-09-2313:32:50|ip=40.80.31.153|method=GET|url=/api/foo/bar?params=everything|status=200|time=9.962|bytes=129|referrer="-"|user-agent="Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/535.7(KHTML,likeGecko)Chrome/16.0.912.63Safari/535.7"|cookie="-" date=2017-09-2313:32:50|ip=40.80.31.153|method=GET|url=/api/foo/bar?params=nothing|status=200|time=11.822|bytes=121|referrer="-"|user-agent="Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/535.7(KHTML,likeGecko)Chrome/16.0.912.63Safari/535.7"|cookie="-"
不同的服务对应的日志可能不一样,本文使用示例日志的格式是:
date|ip|method|url|status|time|bytes|referrer|user-agent|cookie
注意:mac系统和linux系统中的命令行为可能不同,以下命令请在linux系统中使用
排除特殊日志
统计日志时,我们可能不关心HEAD请求,或者只关心GET请求,这里首先需要筛选日志,可以使用grep命令。-v的含义是排除匹配的文本行。
grepGETaccess.log#只统计GET请求 grep-vHEADaccess.log#不统计HEAD请求 grep-v'HEAD\|POST'access.log#不统计HEAD和POST请求
查看接口耗时情况
我们可以将每行的time匹配出来,然后做一个排序。使用awk的match方法可以匹配正则:
awk'{match($0,/time=([0-9]+\.[0-9]+)/,result);printresult[1]}'access.log
awk命令使用方法如下:
awk'{pattern+action}'{filenames}
我们实际上只用到了action:match($0,/time=([0-9]+\.[0-9]+)/,result);printresult[1]这一段。
match方法接收三个参数:需要匹配的文本、正则表达式、结果数组。$0代表awk命令处理的每一行,结果数组是可选的,因为我们要拿到匹配结果所以这里传入了一个result数组,用来存储匹配后的结果。
注意这里的正则我没有使用\d来表示数字,因为awk指令默认使用“EREs",不支持\d的表示,具体请看linuxshell正则表达式(BREs,EREs,PREs)差异比较。
result数组实际上和javascript里的结果数组很像了,所以我们打印出第二个元素,即匹配到的内容。执行完这行命令后结果如下:
9.703 0.337 8.829 9.962 11.822
当然实际上一天的日志可能是成千上万条,我们需要对日志进行排序,且只展示前3条。这里使用到sort命令。
sort命令默认从小到大排序,且当作字符串排序。所以默认情况下使用sort命令之后"11"会排在"8"前面。那么需要使用-n指定按数字排序,-r来按从大到小排序,然后我们查看前3条:
awk'{match($0,/time=([0-9]+\.[0-9]+)/,result);printresult[1]}'access.log|sort-rn|head-3
结果:
11.822 9.962 9.703
查看耗时最高的接口
当然我们一般不会只查看接口耗时情况,还需要把具体日志也打印出来,上面的命令就不能满足要求了。
awk的打印默认是按空格分隔的,意思是2017-09-23GET这一行如果使用awk'{print$1}'会打印出"2017-09-23",类似地,$2会打印出GET。
根据日志特征,我们可以使用|来作为分隔符,这样就能打印出各个我们感兴趣的值了。因为我们想找出耗时最高的接口,那么我们把time、date和url单独找出来。
awk的-F参数用来自定义分隔符。然后我们可以数一下三个部分按|分隔后分别是第几个:time是第6个、date是第1个、url是第4个。
awk-F'|''{print$6$1$4}'access.log
这样打出来结果为:
time=9.703date=2017-09-2313:32:50url=/api/foo/bar?params=something time=0.337date=2017-09-2300:00:00url=/api/foo/healthcheck time=8.829date=2017-09-2313:32:50url=/api/foo/bar?params=anything time=9.962date=2017-09-2313:32:50url=/api/foo/bar?params=everything time=11.822date=2017-09-2313:32:50url=/api/foo/bar?params=nothing
因为我们想按time来排序,而sort可以按列来排序,而列是按空格分隔的,我们目前第一列是time=xxx,是不能排序的,所以这里要想办法把time=给去掉,因为我们很鸡贼地把耗时放在了第一列,那么其实再通过time=进行分隔一下就行了。
awk-F'|''{print$6$1$4}'access.log|awk-F'time=''{print$2}'
结果:
9.703date=2017-09-2313:32:50url=/api/foo/bar?params=something 0.337date=2017-09-2300:00:00url=/api/foo/healthcheck 8.829date=2017-09-2313:32:50url=/api/foo/bar?params=anything 9.962date=2017-09-2313:32:50url=/api/foo/bar?params=everything 11.822date=2017-09-2313:32:50url=/api/foo/bar?params=nothing
使用sort的-k参数可以指定要排序的列,这里是第1列;再结合上面的排序,就能把耗时最高的日志打印出来了:
awk-F'|''{print$6$1$4}'access.log|awk-F'time=''{print$2}'|sort-k1nr|head-3
结果:
11.822date=2017-09-2313:32:50url=/api/foo/bar?params=nothing 9.962date=2017-09-2313:32:50url=/api/foo/bar?params=everything 9.703date=2017-09-2313:32:50url=/api/foo/bar?params=something
统计请求次数最多的接口
如果需要统计哪些接口每天请求量是最多的,只需要新引入uniq命令。
我们已经可以通过grep-vHEADaccess.log|awk-F'|''{print$4}'来筛选出所有的url,uniq命令可以删除相邻的相同的行,而-c可以输出每行出现的次数。
所以我们先把url排序以让相同的url放在一起,然后使用uniq-c来统计出现的次数:
grep-vHEADaccess.log|awk-F'|''{print$4}'|sort|uniq-c
因为示例日志数量太少,我们假设日志里有多条,那么结果应该类似下面:
1url=/api/foo/bar?params=anything 19url=/api/foo/bar?params=everything 4url=/api/foo/bar?params=nothing 5url=/api/foo/bar?params=something
接下来再sort即可:
grep-vHEADaccess.log|awk-F'|''{print$4}'|sort|uniq-c|sort-k1nr|head-10
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。