awk日志处理

作者: classtag | 来源:发表于2016-01-14 00:08 被阅读272次

    前言

    这两天自己挽起袖子处理日志,终于把AWK给入门了。其实AWK的基本使用,学起来也就半天的时间,之前总是靠同事代劳,惰性呀。

    此文仅为菜鸟入门,运维们请勿围观。

    本文转载直网络,如有版权问题,请及时与我联系

    下面是被处理的日志的示例,不那么标准,但不标准的日志正是标准的情况。

    [2015-08-20 10:00:55.600] - [192.168.0.73/192.168.0.75:1080 com.vip.xxx.MyService_2.0 0 106046 100346 90ms 110ms]
    

    基本语句

    最基本的语句,以空格做分割,提取所需的列:

    awk '{print $0,$1,$2,$(NF-1),$NF,$NF-$(NF-1)}’ access.log
    

    1. 输入

    AWK是针对文件或管道中每行输入的处理语言。所以也可以从管道输入:

    grep “xxx” access.log | awk '{print $1}’
    

    但下面这样写就会成为一个Linux老梗的主角,awk不需要不需要cat的。

    cat access.log | awk '{print $1}'
    

    2.语句定义

    可以快速的用单引号’ ’,把所有语句写成一行。

    也可以用-f 指定文件,文件里可以任意换行,增加可读性和重用性。

    所有执行语句用{}括起来,{}的外面是一些高级的东西比如过滤条件,见后。

    3. 列引用

    $0代表整行所有数据,$1代表第一列(终于不是程序员数数从0开始了)。

    NF是个代表总列数的系统变量,所以$NF代表最后一列,还支持$(NF-1)来表示倒数第二列。

    还支持列之间的运算,如$NF-$(NF-1)是最后两列的值相减。

    只写一个print 是 print $0的简写,打印整行所有数据。

    4. 输入的列分隔符

    默认以空格做分割符,也可以重新指定,下例指定了':'

    awk -F ':' '{print $1,$2}’ access.log
    

    也可以正则表达式定义多个分割符,下例指定了 '-' 和 ':'

    awk -F '[-:]' '{print $1,$2}’ access.log
    

    5. 输出的列间隔

    print $1,$2 中间的','逗号,代表打印时第1与第2列之间使用默认分隔符号也就是空格,也可以用” ”来定义其他任意的字符:

    awk '{print $1 "\t" $2 " - " $3$4xxxxx$5}’ access.log
    

    上例,在第1第2列之间用 tab 分隔,第2第3列之间用" - "分隔,

    也可以什么都不写代表中间没分隔,比如第3第4列之间,或者乱写一些字符没用" "括起来,也等于没写,比如第4第5列之间。

    数字类型,字符串类型

    虽然上例最后两列的值是字符串类型的,带着ms字样,看起来不能做算术运算。

    但其实两个列相减时,AWK就会神奇地把它们转换为纯数字。同样,做累计的时候,sum=sum+$NF,也能自动转换为数字。

    如果想对某个字符列比较是否大于阀值,先把它转回数字就行了

    sed "s|ms]||g" access.log | awk ' $NF>100 {print}'
    

    其实可以简写成下面的样子,性能还比使用sed略快:

    awk ' $NF*1>100 {print}’ access.log
    

    awk ' int($NF)>100 {print}’ access.log
    

    BEGIN与END语句

    BEGIN与END后的语句定义在处理全部文本内容之前与之后的语句。

    1.计算累计值和平均值

    awk '{sum+=$NF} END {print sum, sum/NR}'
    

    上例对每行输入内容进行最后一列的值的累计,而END后的语句,打印累计结果 和平均值,NR是系统变量代表总行数。

    2.打印表头

    还可以定义BEGIN语句打印表头,定义变量什么的。

    awk 'BEGIN{print "Date\t\tTime\t\tCost”} {print $1 "\t"$2 "\t" $NF}’ access.log
    

    上例表头用两个制表符分隔,内容则用一个制表符分隔,有良好的对齐效果。

    过滤行

    1. 简单字符匹配

    先用grep过滤也是可以的,也可以用awk简单在执行语句之外的/ /之间定义正则表达式

    awk '/192.168.0.4[1-5]/ {print $1}’ access.log
    

    等价于

    grep "192.168.0.4[1-5]” access.log| awk ‘{print $1}
    

    2. 针对某一列的字符匹配

    针对第4列的地址段匹配,~ 是字符匹配,!~则是不匹配的意思。

    awk '$4 ~ /192.168.0.4[1-5]/ {print}'
    

    3. 针对数值的过滤

    支持==, !=, , >, =, >=

    awk '$(NF-1)*1==100 {print}'
    awk '$NF-$(NF-1)>100 {print}'
    

    见前,对于非纯数字的字段,可以用算术运算让它转回数字。

    4. 多条件同时存在

    awk '($12 >150 || $(13)>250) {print}'
    

    5. 使用if语句

    如果逻辑更复杂,可以考虑使用if,else等语句

    awk '{ if ($(NF-1)*1>100) print}'
    

    其他

    1.外部传入参数

    比如从外面传入超时的阀值,注意threshold在命令行中的位置。

    awk '{if($(NF)*1>threshold) print}' threshold=20 access.log
    

    2.常用函数

    最有用是gsub和sub,match,index等。其中gsub将一个字符串替换为目标字符串,可选定整行替换或只替换某一列。

    awk '{gsub("ms]","",$NF); if( $NF>100 ) print}' access.log
    

    一些例子

    1.截取日期段内段数据

    方式有很多,都是随着日志格式不同自由发挥。

    比如下段截取17:30:30 秒到 17.31:00的数据,先抽取出时分秒三列,再拼成一个数字进行比较

    awk -F "[ :.]" '$2$3$4>=173030 $2$3$4173100 {print}'
    

    也可以匹配某个整点时间, 下例取11点的日志:

    awk '/[2015-08-20 11:/ {print $1}’ access.log
    

    取11点01分到05分的数据:

    awk '/[2015-08-20 11:0[1-5]:/ {print $1}’ access.log
    

    2. 找出超时的数据集中发生的时间

    第一段找出超时记录,第二段过滤掉时间戳里的微秒,然后按秒来合并,并统计该秒超时的次数。

    awk '$(NF)*1>100 {print}’ access.log | awk -F"." '{print $1}' | sort | uniq -c
    

    相关文章

      网友评论

        本文标题:awk日志处理

        本文链接:https://www.haomeiwen.com/subject/rlnckttx.html