Linux 日志异常排查与案例实践

1次阅读

journalctl 查不到日志主因是默认仅存内存日志且未启用持久化,需配置 storage=persistent 并重启 systemd-journald;grep 失效因输出含干扰字段,应改用 -o json + jq 过滤;服务无日志常因 stdout/stderr 未重定向至 journal。

Linux 日志异常排查与案例实践

journalctl 查不到最近的日志?先确认日志存储模式

默认情况下,journalctl 只读内存日志(RuntimeMaxUse= 未配置时可能只保留最近几小时),重启后就丢。这不是 bug,是 systemd-journald 的默认行为。

  • 检查当前日志存储位置:journalctl --disk-usage —— 如果显示 0B,说明没启用持久化
  • 启用持久化:创建 /etc/systemd/journald.conf.d/persistent.conf,写入:
    [Journal] Storage=persistent RuntimeMaxUse=512M MaxRetentionSec=3month
  • 重启服务:sudo systemctl restart systemd-journald;注意旧日志不会自动补回,只从重启后开始落盘
  • 常见误操作:只改了 /etc/systemd/journald.conf 主文件但没 reload,或改完忘记重启服务,journalctl --system 仍查不到历史

grep 日志时匹配不到关键词?注意时间、单位和字段隔离

journalctl 默认输出带时间戳和优先级前缀,直接 grep "Error" 很容易漏掉真正含 error 的业务日志,因为匹配被时间戳或 INFO 字段干扰。

  • -o json 输出结构化数据再过滤更可靠:journalctl -u nginx.service -o json | jq 'select(.MESSAGE | contains("timeout"))'
  • 时间范围必须明确:journalctl --since "2024-05-20 14:00:00"--since "2 hours ago" 更准,后者受系统时钟跳变影响
  • 避免模糊匹配:journalctl | grep -i "fail" 可能命中 failed to start(系统级)和 user_login_failed(应用级),建议加 -u_PID 限定上下文
  • 注意单位大小写:--since "2h" 有效,--since "2H" 会报错 Failed to parse relative time

服务崩溃后 journalctl 显示 no logs?检查 SyslogIdentifier 和 stdout 重定向

很多 Go/Python 服务默认不刷 stdout/stderr 到 journald,或者用了自定义日志库(如 logrus 设为 json 格式但没配 journalhook),导致 journalctl -u myapp 空空如也。

  • 验证是否真的没日志:先用 journalctl _COMM=myapp(按进程名查),比 -u 更底层,能捕获非 systemd 启动的实例
  • 检查服务 unit 文件中是否有 StandardOutput=journalStandardError=journal —— 缺一不可,否则输出直接进 /dev/NULL
  • Go 程序若用 log.printf 但没调 log.SetOutput(os.Stderr),日志可能静默丢失;Python 若用 Logging.basicConfig() 但没设 handlers=[logging.StreamHandler(sys.stderr)],同样不进 journal
  • 临时调试:启动服务时加 ExecStart=/usr/bin/myapp 2>&1 | logger -t myapp,强制走 syslog 兜底

日志量突增导致磁盘打满?别只删 /var/log/journal

rm -rf /var/log/journal/* 是最危险的“快速解法”——它可能破坏 journal 索引,后续 journalctlInvalid argument 或直接卡死。

  • 安全清理命令:journalctl --vacuum-size=500Mjournalctl --vacuum-time=2weeks,journald 自动重建索引
  • 限制单服务日志量:在 service unit 文件里加 SystemMaxUse=100M(全局)或 RuntimeMaxUse=50M(运行时),需配合 Storage=volatilepersistent
  • 高频日志源头常是健康检查失败循环打印,比如 etcd 成员连不上时每秒打一条 context deadline exceeded —— 这类要先停服务再查网络,不是靠删日志解决
  • 监控建议:用 journalctl --disk-usageprometheus exporter 的采集指标,而不是等磁盘 100% 才发现

日志排查真正的难点不在命令怎么敲,而在于分清「是日志没产生」「产生了但没存下来」「存下来了但查法不对」——这三个环节任何一个断掉,journalctl 都会显得很沉默。

text=ZqhQzanResources