Linux 日志管理与分析实战

3次阅读

journalctl查不到日志需先确认服务是否由systemd管理;非systemd启动的服务日志不进journal,应查对应文件;配置storage=persistent并重启journald才能持久化日志。

Linux 日志管理与分析实战

journalctl 查不到服务日志?先确认服务是否用 systemd 管理

很多新手直接 journalctl -u nginx 却返回“no entries”,不是命令错了,而是 nginx 根本没被 systemd 启动——比如你手动跑的 /usr/sbin/nginx,它压根不进 journal。

  • systemctl list-units --type=service | grep nginx 看服务是否注册且状态为 loaded
  • 如果服务存在但 Active:inactive (dead),先 sudo systemctl start nginx 再查
  • 非 systemd 启动的服务(如用 screen 或 nohup 跑的),日志默认写到文件(如 /var/log/nginx/access.log),journalctl 天然看不到
  • 某些发行版(如 centos 7)默认关闭 ForwardToJournal=yes,需在 /etc/systemd/system.conf 中显式开启并 sudo systemctl daemon-reload

grep 日志时匹配不到关键词?注意 journalctl 的输出格式和缓冲行为

journalctl -u sshd | grep "Failed password" 经常漏掉内容,因为 journalctl 默认按分页器输出,且部分字段(如 MESSAGE)可能被截断或转义;更关键的是,未加 -o short-precise-o json 时,时间戳和优先级字段干扰匹配。

  • 优先用 journalctl -u sshd -o cat | grep "Failed password" ——-o cat 去掉元数据,只留纯消息体
  • 想精确匹配某字段(如 SYSLOG_IDENTIFIER),用 journalctl _SYSTEMD_UNIT=sshd SYSLOG_IDENTIFIER=sshd | grep ...
  • 实时跟踪时别用管道接 grep,而用 journalctl -u sshd -f -o cat | grep --line-buffered "Failed",否则 grep 缓冲会导致延迟
  • 注意大小写:默认 grep 区分大小写,失败登录日志里可能是 failedFailed,加 -i 更稳妥

日志刷屏太快撑爆磁盘?控制 journald 存储策略不能只靠 /var/log/journal

/var/log/journal 目录存在 ≠ 日志就一定存那儿——journald 默认启用 Storage=auto,若该目录不可写或权限不对,会自动 fallback 到 /run/log/journal(内存临时目录),重启即丢,根本起不到归档作用。

  • 先运行 journalctl --disk-usage 看实际用了多少空间,再查配置位置:journalctl --all --no-pager | head -n 10 看第一行提示的 storage 路径
  • 编辑 /etc/systemd/journald.conf,设 Storage=persistent(强制落盘),并配 SystemMaxUse=500MMaxRetentionSec=2week
  • 改完必须执行 sudo systemctl restart systemd-journald,否则配置不生效;旧日志不会自动清理,要手动 sudo journalctl --vacuum-size=400M
  • 注意 SElinux:CentOS/RHEL 上若启用了 enforcing 模式,/var/log/journal 目录需有 system_u:object_r:var_log_t:s0 上下文,否则 journald 拒绝写入

想导出结构化日志做分析?别直接 parse journalctl 文本输出

journalctl -o json 导出 JSON 是对的,但直接用 shell 脚本 jq '.MESSAGE | select(contains("timeout"))' 容易崩——因为 journal 的 JSON 输出是每行一个 JSON 对象(JSONL),但某些字段(如 MESSAGE)含换行符或双引号,jq 默认解析会报错。

  • 安全做法是加 --all--no-hostname 减少干扰字段:journalctl -u app --since "2024-01-01" -o json --all --no-hostname
  • jq -r 'select(.MESSAGE and (.PRIORITY | tonumber 过滤错误级日志,注意 <code>.PRIORITY字符串,得转数字比对
  • 批量处理大日志时,避免 journalctl -o json | jq 管道阻塞,改用 journalctl -o json --output-fields=MESSAGE,PRIORITY,_PID --since "1 hour ago" > logs.jsonl,再用 Python 或 awk 处理
  • 不要依赖 _HOSTNAME 字段做机器识别——容器环境里它常是容器 ID,不如用 _MACHINE_ID 或自定义 SYSTEMD_LOG_LEVEL=debug 注入标识

真正麻烦的从来不是查哪条日志,而是日志源头没打全字段、服务启动方式绕过 systemd、或者磁盘快满时 journald 默默切到内存模式却没人发现。这些点不在文档首页,但一出问题就卡半天。

text=ZqhQzanResources