日志无精确时间戳时如何用awk筛选日期范围值并统计计数
日志指定时间范围AAA-passed计数实现方案
问题描述
需要从固定格式的日志中统计指定时间区间内AAA-passed类型的记录条数,日志样例如下:
# values.log 文件内容 2022-01-01-10:01 AAA-passed 2022-01-01-11:05 AAA-passed 2022-01-01-12:01 AAA-passed 2022-01-01-13:05 AAA-passed 2022-01-02-12:01 AAA-failed 2022-01-03-13:05 AAA-failed
最初使用的awk区间匹配写法,依赖日志中存在与起止时间完全一致的精确时间戳,当日志中不存在传入的起止时间点时,会返回错误统计结果。原问题代码如下:
t1='2022-01-01-10:01' t2='2022-01-03-13:05' pass=$(awk '/^'$t1.*'/,/'$t2.*'/' values.log | grep -w "AAA-passed" | wc -l) echo $pass
例如传入t1='2022-01-01-10:00'、t2='2022-01-03-14:00'时,由于日志中不存在这两个精确时间点,上述命令无法得到正确结果。
实现步骤
找到的非精确匹配awk脚本依赖固定时间格式,且不支持动态传参,按以下两步修改即可满足需求:
1. 调整时间生成格式
不需要硬套参考脚本里的年-月-日 时:分:秒.毫秒格式,你的日志时间前缀为年-月-日-时:分,该格式的字符串字典序和实际时间先后顺序完全一致,可以直接做大小比对,只需要让date生成和日志时间前缀格式一致的起止时间即可:
# 生成7天前到当前时刻的起止时间,格式与日志时间前缀完全匹配 t1=$(date -d "${dtd} -7 days" +'%Y-%m-%d-%H:%M') t2=$(date '+%Y-%m-%d-%H:%M')
2. 改造awk脚本完成统计
通过awk的-v参数传入动态生成的起止时间,在awk内部同时完成时间范围判断和目标记录计数,不需要额外嵌套grep、wc命令:
pass=$(awk -v start="$t1" -v end="$t2" ' # 匹配符合时间格式开头的有效日志行 /^[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{2}:[0-9]{2}/ { # 截取每行前16位的时间戳部分 ts = substr($0, 1, 16) # 判断当前行是否在指定时间范围内 inrange = ts >= start && ts <= end } # 时间范围内且为AAA-passed的行累计计数 inrange && /AAA-passed/ { count++ } # 所有行处理完成后输出计数结果,无匹配时输出0 END { print count + 0 } ' values.log) echo $pass
方案特性
- 不依赖起止时间点在日志中存在,只要日志行时间戳落在
[start, end]闭区间内就会被统计 - 时间比对直接用字符串字典序实现,不需要转unix时间戳,逻辑简单执行效率高
- 所有逻辑在单个awk进程中完成,减少管道嵌套的性能开销
- 无匹配记录时默认返回0,不会出现空值
- 测试验证:传入
t1='2022-01-01-10:00'、t2='2022-01-03-14:00'时,统计结果为4,与预期一致。
内容的提问来源于stack exchange,提问作者Kasun Wimaladarma
相关产品推荐
相关产品推荐

