通过使用shell命令,您可以轻松统计和分析日志。当服务出现异常时,需要查看日志,因此掌握一种统计日志的技巧是必不可少的。假设有一个包含以下内容的日志文件access.log。我们以这个文件的日志为例。日期=2017-09-2313:32:50|ip=40.80.31.153|方法=获取|url=/api/foo/bar?params=something|状态=200|时间=9.703|字节=129|推荐人=“-”|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|方法=头|url=/api/foo/healthcheck|状态=200|时间=0.337|字节=10|推荐人=“-”|用户代理=“-”|cookie="-"date=2017-09-2313:32:50|ip=40.80.31.153|方法=获取|url=/api/foo/bar?params=任何东西|状态=200|时间=8.829|字节=466|推荐人=“-”|用户代理=“GuzzleHttp/6.2.0curl/7.19.7PHP/7.0.15”|cookie="-"date=2017-09-2313:32:50|ip=40.80.31.153|方法=获取|url=/api/foo/bar?params=一切|状态=200|时间=9.962|字节=129|推荐人=“-”|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|方法=获取|url=/api/foo/bar?params=nothing|状态=200|时间=11.822|字节=121|推荐人=“-”|user-agent="Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/535.7(KHTML,likeGecko)Chrome/16.0.912.63Safari/535.7"|cookie="-"不同服务对应的日志可能不同。本文使用的示例日志格式为:日期|知识产权|方法|网址|状态|时间|字节|推荐人|用户代理|cookie注意mac系统和linux系统的命令行为可能不同。请在linux系统中使用以下命令排除特殊日志。在统计日志的时候,我们可能不关心HEAD请求,或者只关心GET请求,那么需要先对日志进行过滤,可以使用grep命令-v的方式排除匹配的文本行。grepGETaccess.log#只统计GET请求grep-vHEADaccess.log#不统计HEAD请求grep-v'HEAD\|POST'access.log#不统计HEAD和POST请求查看耗时情况接口的我们可以记录每一行的时间是匹配的,然后做一个排序。使用awk的match方法匹配正则表达式:awk'{match($0,/time=([0-9]+\.[0-9]+)/,result);printresult[1]}'access.logawk命令使用如下:awk'{pattern+action}'{filenames}我们实际上只使用action:match($0,/time=([0-9]+\.[0-9]+)/,结果);打印result[1]这一段。match方法接收三个参数:要匹配的文本、正则表达式和结果数组。$0代表awk命令处理的每一行,result数组是可选的,因为我们要得到匹配的结果,所以这里传入一个result数组来存放匹配结果。注意,我这里在正则表达式中没有使用\d来表示数字,因为awk命令默认使用“EREs”,不支持\d的表达式。具体可以参考linuxshell正则表达式(BREs、EREs、PREs)的区别比较。result数组其实和javascript中的result数组很像,所以我们打印出第二个元素,也就是匹配的内容。执行这条命令后,结果如下:9.7030.3378.8299.96211.822当然,一天可能有几万条日志。我们需要对日志进行排序,只显示前三个。这里使用排序命令。sort命令默认从小到大排序,按字符串排序。所以默认情况下,使用排序命令后,“11”将排在“8”之前。然后需要用-n指定按数字排序,-r指定从大到小排序,然后我们看前3项:awk'{match($0,/time=([0-9]+\.[0-9]+)/,结果);打印结果[1]}'access.log|排序-rn|head-3结果:11.8229.9629.703查看最耗时的接口需要打印出具体的log,上面的命令不能满足要求。awk的打印默认是用空格分隔的,也就是说2017-09-23GET这行如果使用awk'{print$1}'会打印“2017-09-23”,同理$2会打印GET。根据日志特点,我们可以使用|作为分隔符,这样我们就可以打印出我们感兴趣的每一个值。因为我们要找出最耗时的接口,所以我们分别找出时间、日期和url。awk的-F参数用于自定义分隔符。那么我们可以统计一下用|隔开的三部分的个数:时间是第6位,日期是第1位,url是第4位。awk-F'|''{print$6$1$4}'access.log打印出结果如下:time=9.703date=2017-09-2313:32:50url=/api/foo/bar?params=somethingtime=0.337date=2017-09-2300:00:00url=/api/foo/healthchecktime=8.829date=2017-09-2313:32:50url=/api/foo/bar?params=anythingtime=9.962date=2017-09-2313:32:50url=/api/foo/bar?params=everythingtime=11.822date=2017-09-2313:32:50url=/api/foo/bar?params=nothing因为我们要按时间排序,排序可以按列排序,列之间用空格隔开。我们当前的第一列是time=xxx,无法排序,所以这里得想办法把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=something0.337date=2017-09-2300:00:00url=/api/foo/healthcheck8.829date=2017-09-2313:32:50url=/api/foo/bar?params=anything9.962date=2017-09-2313:32:50url=/api/foo/bar?params=everything11.822date=2017-09-2313:32:50url=/api/foo/bar?params=nothing使用sort的-k参数指定要排序的列,这里是第一列;结合上面的排序,可以打印出耗时最高的日志:awk-F'|''{print$6$1$4}'access.log|awk-F'time=''{print$2}'|排序-k1nr|head-3结果:11.822date=2017-09-2313:32:50url=/api/foo/bar?params=nothing9.962date=2017-09-2313:32:50url=/api/foo/bar?params=everything9.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'|''{打印$4}'|排序|uniq-c由于样本日志数量太少,我们假设有多个日志,那么结果应该类似如下:1url=/api/foo/bar?params=anything19url=/api/foo/bar?params=everything4url??=/api/foo/bar?params=nothing5url=/api/foo/bar?params=something然后排序:grep-vHEADaccess.log|awk-F'|''{打印$4}'|排序|uniq-c|排序-k1nr|头-10
