一、需求描述
最近接到一个分析异常日志的需求,因为日志内容比较繁杂庞大,因此需要对日志关键异常信息进行过滤,通过awk即可实现。
二、日志格式
日志格式如下,可以主要需要获取的是 异常报错行
和异常类型
。
三、关键信息过滤实现
$0——获取整行
~/ERROR/——匹配带ERROR的行
print $0——输出获取到的整行
(注意print会自动换行,printf不会自动换行)
getline——进入下一行
print $0——输出获取到的整行,实际上就是为了输出下一行
print "\n"——输出换行,使输出更美观。
(如果需要继续对数据进行处理建议使用其他符号划分,比如“-------------”)
awk '$0~/ERROR/{print $0; getline; print $0;print"\n"}' error.log
执行结果如下
如果对于错误提示行,我不想要时间这些无关列,只想要[ERROR]后的列怎么办
$0是获取整行
~/ERROR/——匹配带ERROR的行
print $0——输出获取到的整行
NF——一条记录的字段的数目
{for(i=5;i<=NF;i++) printf $i" ";}——输出ERROR后的所有列,以空格分割
(注意print会自动换行,printf不会自动换行)
getline——进入下一行
print $0——输出获取到的整行,实际上就是为了输出下一行
print "\n"——输出换行,使输出更美观。
(如果需要继续对数据进行处理建议使用其他符号划分,比如“-------------”)
awk '$0~/ERROR/{for(i=5;i<=NF;i++) printf $i" ";printf"\n"; getline; print $0;print"\n"}' error.log
可以看到,输出结果少了很多不需要的信息。
四、关键信息去重并统计
因为最终目的是对异常进行分类和统计,因此这里用=====
进行字段分割,同时不再使用print "/n"多输出一行换行,而是使用printf "\n"在这行数据输出完毕后换行,最终每一行就是异常报错点——异常类型
的格式,将输出进行去重并统计即可。
如果下一行中带有变量,比如请求用户的id等等,可以substring($0,m,n)来截取字符串。
awk '$0~/ERROR/{for(i=6;i<=NF;i++) printf $i" ";printf"====="; getline; print $0;}' error.log |sort|uniq -c | sort -n -r
去重结果如下图所示:
Tips:如果awk提示run for this one很有可能是printf输出的内容带有%
导致的,通过sed命令先去掉文件中的%
即可。
sed -i 's/%//g' 1.log
五、调整后实际应用的Shell脚本及效果
脚本不通用,只提供参考
将脚本放在待分类日志同级目录,然后脚本执行完毕后会在当前目录下新建一个叫statistic的目录,该目录中统计结果文件名 同 原日志文件名。
#!/bin/bash
# 获取当前目录下所有文件名
dir="./"
files=$(ls $dir | grep 'log$')
# 创建用于存储统计后文件的文件夹
mkdir -p ./statistic
# 遍历文件
for file in $files
do
# 如果是log后缀的文件才进行awk操作
echo "正在对$file文件进行sed及awk操作"
# 去除对printf的影响
sed -i 's/%//g' $dir/$file
# 执行awk命令
# if语句判断第六列是否含有:,即我所需要的报错位置信息,若无则将前一列加上即可解决此问题
# substr截断字符串获取关键信息
# getline获取下一行
# uniq -c 去重并在行左侧显示重复次数
# sort -n -r将数字字符按照数字而不是字符来排序
# > 将结果输出到某文件
# 因为有些行不存在异常类型输出,因此这里判断下一行是否含有异常报错位置行的某一特殊标识
awk '$0~/\[ERROR\]/{if(!match($6,":")) printf $5;printf substr($6,1,70);printf"====="; getline; if(!match($0,"QTraceId") && !match($0,"ERROR")) printf substr($0,1,60); printf "\n" }' $dir/$file |sort|uniq -c | sort -n -r > $dir/statistic/$file
done
echo "执行统计分类完毕,结果在当前目录/statistic文件夹下"
效果如下,最终以频次 异常报错位置=====异常类型
的格式输出