awk命令新手求助:日志异常单行化+按时间戳与关键词过滤
解决多行日志的awk过滤问题
作为awk新手,遇到多行日志(比如换行的异常堆栈)确实容易踩坑——毕竟默认awk是按行处理的,没法识别跨多行的单条日志。我来给你个实用的解决方案,核心思路是先把跨多行的日志合并成单行,再做过滤和搜索。
第一步:明确日志边界
首先得抓住你的日志特征:通常每条完整日志的开头都会有时间戳,而换行的异常信息行是没有的。比如你的日志时间戳是[YYYY-MM-DD HH:MM:SS]格式,那我们就用这个正则来识别每条日志的起始点。
第二步:编写awk处理脚本
下面这个脚本会帮你完成「多行日志合并+指定字符串搜索+时间范围过滤」三个需求:
BEGIN { # 替换成你要搜索的目标字符串,比如"ERROR" target_str = "你的搜索关键词" # 替换成你需要的时间范围,格式要和日志里的时间戳完全一致 start_time = "2024-05-20 00:00:00" end_time = "2024-05-21 23:59:59" } # 匹配时间戳开头的行,作为单条日志的起始 /^\[([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})\]/ { # 如果之前有累积的日志行,先检查是否符合过滤条件,符合就输出 if (line != "") { if (index(line, target_str) != 0 && compare_time(log_time, start_time) >= 0 && compare_time(log_time, end_time) <= 0) { print line } } # 提取当前日志的时间戳(去掉前后的[]) log_time = substr($0, 2, 19) # 初始化当前日志行 line = $0 next } # 非时间戳开头的行,追加到当前日志行(用|分隔原换行内容,方便区分) { line = line " | " $0 } # 处理最后一条日志,避免遗漏 END { if (line != "") { if (index(line, target_str) != 0 && compare_time(log_time, start_time) >= 0 && compare_time(log_time, end_time) <= 0) { print line } } } # 自定义时间比较函数:把时间转成秒数,方便判断是否在范围内 function compare_time(t1, t2) { split(t1, t1_parts, /[- :]/) split(t2, t2_parts, /[- :]/) # mktime函数把时间转成从1970年开始的秒数,忽略闰年日常使用足够 t1_sec = mktime(t1_parts[1] " " t1_parts[2] " " t1_parts[3] " " t1_parts[4] " " t1_parts[5] " " t1_parts[6]) t2_sec = mktime(t2_parts[1] " " t2_parts[2] " " t2_parts[3] " " t2_parts[4] " " t2_parts[5] " " t2_parts[6]) return t1_sec - t2_sec }
第三步:使用方法
- 把上面的脚本保存为
process_log.awk文件 - 运行命令处理你的日志文件(比如
app.log):
awk -f process_log.awk app.log
或者直接把脚本写在命令行里执行,省去保存文件的步骤。
关键调整点
- 时间戳适配:如果你的日志时间戳格式不是
[YYYY-MM-DD HH:MM:SS](比如是YYYY-MM-DDTHH:MM:SS),要修改匹配的正则表达式,以及substr的参数来正确提取时间戳。 - 分隔符替换:脚本里用
|连接换行的异常内容,你可以换成其他不冲突的符号(比如>>>)。 - 兼容性提示:建议用GNU awk(gawk),它的
mktime函数兼容性更好,大部分Linux系统默认就是gawk。
举个实际效果例子,假设你的日志里有这样的多行异常:
[2024-05-20 10:05:00] ERROR: Failed to process request java.lang.NullPointerException at com.example.Service.process(Service.java:42)
运行脚本后会输出合并后的单行:
[2024-05-20 10:05:00] ERROR: Failed to process request | java.lang.NullPointerException | at com.example.Service.process(Service.java:42)
这样就能精准过滤出包含目标字符串、时间在指定范围内的日志,而且把多行异常合并成了单行,完美解决你之前的问题。
内容的提问来源于stack exchange,提问作者grahul
相关产品推荐
相关产品推荐

