日常筛日志时通过ELK去查询的,但是如果脱离工具如何来做?

通常我们是用ELK去查询过滤的,如果脱离工具,需要运维导出日志,或者直接用grep sed awk 命令搭配正则或者编写shell脚本供运维执行后导出分析

通常查找出错误日志 cat error.log | grep ‘nick’ , 这时候我们还有个需求就是输出当前这个日志的前后几行:

1
2
3
cat error.log | grep -C 5 'nick' 显示file文件里匹配foo字串那行以及上下5
cat error.log | grep -B 5 'nick' 显示foo及前5
cat error.log | grep -A 5 'nick' 显示foo及后5

在日常系统维护、问题排查时,经常需要对系统后台日志进行筛选过滤。如果对特定时间段的日志进行筛选,该如何编写Shell脚本(命令)呢?本文给出三种常用的Shell编写方法:grep、gawk和sed。

日志筛选需求描述:从2017年12月22日的日志文件中,统计时间段13:30~18:00之间包含筛选词“open.app”的日志行数。

本系统后台日志格式如下图所示:
从图中可以看出每行日志以“yyyy-MM-dd HH:mm:ss”开头,故要筛选一段时间的日志,就要匹配该日志的时间前缀。
接下来文章分别介绍使用grep、gawk和sed命令,如何进行相关的Shell脚本(命令)的编写。

1grep命令

在日志筛选、搜索中,grep是使用频率较高的命令。对于grep命令来说,如果筛选一段时间的日志,需要进行多条件相并过滤,使用正则表达式进行处理。对于13:30~18:00时间段来说,可以转化为下面表格多个时间相并。
序号 筛选条件 筛选时间段

1
2
3
4
5
6
7
1 2017-12-22 13:3 13:30:00~13:39:59
2 2017-12-22 13:4 13:40:00~13:49:59
3 2017-12-22 13:5 13:50:00~13:59:59
4 2017-12-22 14 14:00:00~14:59:59
5 2017-12-22 15 15:00:00~15:59:59
6 2017-12-22 16 16:00:00~16:59:59
7 2017-12-22 17 17:00:00~17:59:59

命令如下:

1
grep -E '^2017-12-22  13:3|^2017-12-22 13:4|^2017-12-22 13:5|^2017-12-22 14|^2017-12-22  15|^2017-12-22 16|^2017-12-22 17' 2017-12-22.log.txt | grep  'open.app' | wc -l

运行结果如下图:
共检索筛选到71314条。
上述命令条件可以使用正则表达式进行缩减,命令如下:

1
grep -E '^2017-12-22  13:[3,4,5]|^2017-12-22 1[4,5,6,7]' 2017-12-22.log.txt | grep  'open.app' | wc -l

运行结果如下图所示:
检索筛选到71314条,和上述命令一致。

2gawk命令

gawk命令是功能强大、可编程的Linux命令。使用gawk命令筛选一段时间的日志,其思路是首先截取出每行日志的“yyyy-MM-dd HH:mm:ss”19位时间前缀,然后将该前缀字符串与“2017-12-22 13:30:00”、“2017-12-22 18:00:00”进行比较,不在该范围的日志则丢弃。
命令脚本如下所示:

1
cat 2017-12-22.log.txt  | gawk '{    time = substr($0, 1, 19);         if(('2017-12-22 13:30:00' <= time)="" &&=""  (time="">< '2017-12-22="" 18:00:00'))="">         {             print($0);         }}' | grep  'open.app' | wc -l

运行结果如下图所示:
共检索筛选到71314条。
注:需要注意“2017-12-22 18:00:00”使用的是小于符号,而不是小于等于符号。

3sed命令

sed是一种流编辑器命令,它是文本处理中非常中的工具,能够完美的配合正则表达式使用。使用sed命令选定行的范围语法,既是逗号语法。
命令如下所示:

1
sed -n '/2017-12-22  13:30:00/,/2017-12-22 18:00:00/p' 2017-12-22.log.txt | grep  'open.app' | wc -l

运行结果如下图所示:
共检索筛选到71314条。
注:该sed命令含义是选定行范围:从第一行“2017-12-22 13:30:00”开始,到第一行“2017-12-22 18:00:00”结束,包括第一行“2017-12-22 18:00:00”。如果不筛选“open.app”关键字,单纯计数,则sed命令比如上述grep和gawk命令多筛选出一条。

4命令比较

对命令运行时间和命令编写的复杂性进行对比,结果如下表所示:
命令 耗时(秒) 命令复杂性
grep 50 低
gawk 122 高
sed 61 低
从表中可以看出,grep命令运行时间最短;gawk命令运行时间最长,而且命令编写较为复杂。另外sed命令运行时间跟grep相近,但是sed命令对时间段适应性较好。如果时间段扩大,grep命令修改较大,而sed命令修改较小。

筛选15:05–15:10期间的日志
使用sed

1
sed -n '/Apr 22 15:05/,/Apr 22 15:10/p' syslog > test

使用grep,与sed提取的行数有差异,待查验。

1
grep -E '^Apr 22 15:05|^Apr 22 15:06|^Apr 22 15:07|^Apr 22 15:08|^Apr 22 15:09|^Apr 22 15:10'

使用awk,跟grep提取行数一致,不过会因为分隔符原因,时间戳格式被修改,需要额外辨别,待完善。

1
awk -F'[:]' '$1 = 15 && $2 >=5 && $2 <= 10 {print $0}' syslog

linux下使用awk命令按时间段筛选日志

1
2
zcat com.log20160529.gz | grep 'dianping_reply'| 
awk '{split($4,array,"[");if(array[2]>="29/May/2016:00:00:26" && array[2]<="29/May/2016:00:01:14"){print $0}}'

扫描gz压缩文件,从中寻找带有dianping_reply的行,将改行按照[进行拆分,然后直接使用if条件进行判断,比较,最终输出想要的结果。
zcat 直接读取压缩文件的内容
grep用来过滤特定字符的行
awk 用来执行命令
split用来切分字符串