Linux 日志过滤与分析命令实战

1次阅读

grep搜不到关键词主因是大小写敏感,应加-i参数;日志可能含ansi字符、被压缩或分隔符不统一,需用cat -v、zgrep、awk -f’s+’或jq等针对性处理。

Linux 日志过滤与分析命令实战

grep 筛日志时为什么搜不到明明存在的关键词?

常见现象是 grep "Error"/var/log/syslog 里没结果,但用 less 手动翻又确实有。根本原因通常是日志行被截断、编码异常,或更常见的是——日志里实际写的是 error(小写)或 Error(首字母大写),而 grep 默认区分大小写。

  • -i 参数做不区分大小写的匹配:grep -i "error"
  • -E 支持正则,比如匹配 ERROR/Warning/CRITICAL:grep -E "(ERROR|Warning|CRITICAL)"
  • 注意日志可能含 ANSI 转义字符(尤其容器日志),先用 cat -v 看真实内容,必要时用 sed 's/x1b[[0-9;]*m//g' 清洗
  • 如果日志是压缩的(如 syslog.1.gz),直接 zgrep 更省事:zgrep -i "timeout" /var/log/syslog.1.gz

用 awk 提取特定字段时字段数总对不上

awk '{print $5}' 在日志里经常打印出空或错位内容,不是 awk 有问题,而是日志分隔符不统一:系统日志常用空格,但有些字段本身含空格(如进程名带路径),还有时间戳里带冒号和中括号。硬按空格切必然崩。

  • 优先用 awk 的固定分隔符模式,比如 systemd 日志用 -F' ' 不够稳,改用 -F'[[:space:]]+'(多个空白当一个分隔符)
  • 真正可靠的方案是用 awk 配合正则捕获,例如提取 systemd[12345] 中的 PID:awk '/systemd[[0-9]+]/ {match($0, /systemd[([0-9]+)]/, arr); print arr[1]}'
  • 若日志是 json 格式(如 docker 或 fluentd 输出),别硬啃 awk,直接上 jqdocker logs myapp | jq -r '.level, .message'

tail -f 实时看日志卡住或漏行

tail -f /var/log/auth.log 有时突然不动,或者新日志来了但终端没刷新。这不是网络问题,而是日志轮转(logrotate)触发后,tail 还锁着旧文件句柄,新内容写进新文件,它就“失联”了。

  • -F(大写 F)替代 -ftail -F /var/log/auth.log,它会自动跟踪文件名,轮转后重新打开新文件
  • 如果日志写入频繁但缓冲大(如某些 Java 应用),可能因 stdout 缓冲导致 tail 看不到实时输出;此时需在应用侧加 -Djava.util.Logging.Simpleformatter.format="%1$tF %1$tT %4$s %2$s %5$s%6$s%n" 并禁用缓冲,或用 stdbuf -oL 启动
  • tail -n 100 -F 每次重启都重读最后 100 行,适合调试;但生产环境慎用,避免 IO 毛刺

日志量太大时 grep + awk 组合变慢甚至 OOM

查一周的 /var/log/journalnginx access.log 十几 G,grep "500" *.log | awk '{print $1}' | sort | uniq -c 很容易卡死或被系统 kill —— 因为管道把全量数据拖进内存,中间步骤还重复扫描。

  • journalctl 原生过滤代替文本处理:journalctl -S "2024-04-01" -U "2024-04-07" -p err -o short-iso,它走二进制索引,秒级响应
  • 对普通文本日志,先用 awk 做单遍过滤输出关键字段,再交给 sort | uniqawk '$9 ~ /^500$/ {print $1}' access.log | sort | uniq -c | sort -nr
  • 实在要高频分析,别硬扛,导出到 sqlitetsvcsvsql 查,比 shell 管道稳定得多

日志格式千差万别,没有银弹命令。最常被忽略的是确认日志源头是否做了结构化输出,以及轮转策略是否影响了你的路径假设——比如以为 /var/log/nginx/access.log 是主文件,其实它刚被 rename 成 access.log.1,而新日志正往空的 access.log 写。

text=ZqhQzanResources