巧用awk:如何把多行日志变成一行
by katana
有很多同事在统计或者监控过程中遇到这样的问题:
一条日志被打印成多行,我又要分析其中某个域,又要分析用户内容…………
如何处理这种日志呢?
例如:
[2009-05-01 00:00:00] |第一条日志|0|192.168.0.1|Command|Operate|12345678|13800000000|日志内容主菜单。用功能回数字
1主菜单第一行
2主菜单第二行
3主菜单第三行
4主菜单第四行
[2009-05-01 00:00:03] |第二条日志|0|192.168.100.100|Command|Operate|12345678|13800000000|日志功能。用功能回数字
1功能一
2功能二
功能详情用手机登录www.example.com
……………………
都是以回车结尾,每行的域又不一样多,这样统计起来非常不便。
其实这个问题非常简单,我们只要抓住每条日志的特点就可以把多行日志还原成一行:
在上面的例子,我们可以分析得出:一条日志必定是以[日期 时间]开头
那么我只用在遇到"^/[2009-05-01 "的时候换行即可,语句如下(如果你想把日志中的换行用空格代替):
awk -F"|" '{if($0 ~ /^/[2009-05-01 /) {printf "/n%s ",$0} else {printf "%s ",$0}}END{printf "/n"}' test1.log|sed -n '2,$p' > test2.log
结果如下:
[2009-05-01 00:00:00] |第一条日志|0|192.168.0.1|Command|Operate|12345678|13800000000|日志内容主菜单。用功能回数字 1主菜单第一行 2主菜单第二行 3主菜单第三行 4主菜单第四行
[2009-05-01 00:00:03] |第二条日志|0|192.168.100.100|Command|Operate|12345678|13800000000|日志功能。用功能回数字 1功能一 2功能二 功能详情用手机登录www.example.com
即使如果用户内容中含有以"[2009-05-01 "的内容,我们还是可以找到其他特点,比如域个数大于2
只需在awk脚本中加上判断域个数条件:
awk -F"|" '{if($0 ~ /^/[2009-05-01 / && NF > 2 ) {printf "/n%s ",$0} else {printf "%s ",$0}}END{printf "/n"}' test1.log|sed -n '2,$p' > test2.log
注意:
在awk中使用printf函数的时候,要规范使用,要使用%s,以下用法
awk -F"|" '{if($0 ~ /^/[/) {printf "/n"$0" "} else {printf $0" "}}END{printf "/n"}' test1.log|sed -n '2,$p' > test2.log
会报错:
fatal: not enough arguments to satisfy format string
而且这个错误只有在你的日志够多的情况下才会出现,而一般平时用少量日志进行测试的时候不会错,真正执行大日志量的日志时就有问题了。