systemd 教程 / 日志系统(journalctl)
日志系统(journalctl)
一、systemd-journald 简介
systemd-journald 是 systemd 的日志服务,使用二进制格式存储日志,提供结构化查询、完整性校验等能力。
1.1 journald vs syslog 对比
| 特性 | journald | syslog (rsyslog) |
|---|---|---|
| 存储格式 | 二进制 | 纯文本 |
| 结构化数据 | ✅ 支持 | ❌ 需解析 |
| 查询能力 | 字段过滤 | grep 文本 |
| 日志完整性 | Forward Secure Sealing | 无 |
| 日志大小 | 压缩存储 | 无压缩 |
| 启动日志 | ✅ 从最早开始 | 网络服务启动后 |
| 内核日志 | ✅ 原生集成 | 需配置 |
二、journalctl 基础用法
# 查看所有日志(分页显示)
journalctl
# 从最新日志开始查看
journalctl -r
# 只显示最新 N 条
journalctl -n 50
# 实时跟踪日志(类似 tail -f)
journalctl -f
# 查看特定服务的日志
journalctl -u nginx.service
# 跟踪特定服务的实时日志
journalctl -u nginx.service -f
# 查看多个服务的日志
journalctl -u nginx.service -u php-fpm.service
# 指定 PID
journalctl _PID=12345
💡 提示:-u 选项可以多次使用来同时查看多个服务的日志,无需使用管道组合。
2.1 按时间过滤
# 查看今天的日志
journalctl --since today
# 查看最近 1 小时
journalctl --since "1 hour ago"
# 查看指定时间范围
journalctl --since "2026-05-11 08:00" --until "2026-05-11 12:00"
# 查看本次启动的日志
journalctl -b
# 查看上一次启动的日志
journalctl -b -1
# 列出所有启动记录
journalctl --list-boots
| 时间格式 | 示例 |
|---|---|
| 绝对时间 | "2026-05-11 10:30:00" |
| 相对时间 | "1 hour ago"、"5 min ago" |
| 关键字 | today、yesterday、now |
| ISO 8601 | "2026-05-11T10:30:00+08:00" |
三、高级过滤
3.1 按优先级过滤
| 等级 | 名称 | 说明 |
|---|---|---|
| 0 | emerg | 系统不可用 |
| 1 | alert | 需要立即处理 |
| 2 | crit | 严重条件 |
| 3 | err | 错误 |
| 4 | warning | 警告 |
| 5 | notice | 正常但重要 |
| 6 | info | 信息 |
| 7 | debug | 调试 |
# 只显示错误及以上级别
journalctl -p err
# 指定范围(3=err 到 6=info)
journalctl -p 3..6
# 组合使用
journalctl -u nginx.service -p err --since today
3.2 按标识符与字段过滤
# 按 syslog 标识符过滤
journalctl -t nginx
# 查看日志条目的所有字段
journalctl -o verbose -n 1
# 按字段过滤
journalctl _COMM=sshd
journalctl _UID=0
journalctl _HOSTNAME=server1
3.3 组合过滤示例
# nginx 今天的错误日志,最新 20 条
journalctl -u nginx.service -p err --since today -n 20
# SSH 登录失败
journalctl -u sshd.service -p err | grep "Failed"
# 内核从上次启动以来的错误
journalctl -k -b -p err
四、输出格式
# 短格式(默认)
journalctl -o short
# ISO 时间格式
journalctl -o short-iso
# 详细格式(显示所有字段)
journalctl -o verbose
# JSON 格式(便于程序处理)
journalctl -o json
# 美化 JSON
journalctl -o json-pretty
# 仅消息内容(无元数据)
journalctl -o cat
# 导出 JSON 格式日志到文件
journalctl -u nginx.service --since today -o json > /tmp/nginx-logs.json
五、持久化存储
5.1 启用持久存储
journald 默认使用易失存储(/run/log/journal/,重启后丢失)。创建持久目录即可启用:
# 创建持久存储目录
sudo mkdir -p /var/log/journal/
sudo systemd-tmpfiles --create --prefix /var/log/journal/
sudo systemctl restart systemd-journald
# 检查当前存储模式
ls -la /var/log/journal/ 2>/dev/null && echo "持久存储" || echo "易失存储"
5.2 日志大小限制
编辑 /etc/systemd/journald.conf:
[Journal]
SystemMaxUse=500M # 最大磁盘使用
SystemMaxFileSize=50M # 单文件最大大小
SystemKeepFree=1G # 保留最小可用空间
MaxRetentionSec=3month # 最大保留时间
Storage=persistent # 持久存储
# 重载配置
sudo systemctl restart systemd-journald
# 查看当前日志占用空间
journalctl --disk-usage
5.3 日志清理
# 按大小清理(保留最近 100M)
sudo journalctl --vacuum-size=100M
# 按时间清理(保留最近 7 天)
sudo journalctl --vacuum-time=7d
# 按文件数清理(最多 5 个日志文件)
sudo journalctl --vacuum-files=5
六、日志签名与完整性
Forward Secure Sealing (FSS) 用于验证日志完整性,防止篡改:
# 创建密封密钥
sudo journalctl --setup-keys
# 验证日志完整性
sudo journalctl --verify
⚠️ 注意:FSS 密钥有有效期(默认 24 小时),建议配合 cron 定期验证。
七、日志转发
# 转发到传统 syslog
cat > /etc/systemd/journald.conf.d/forward.conf << 'EOF'
[Journal]
ForwardToSyslog=yes
EOF
sudo systemctl restart systemd-journald
配合 rsyslog 转发到远程服务器(/etc/rsyslog.d/remote.conf):
# 转发所有日志到远程 syslog
*.* @@192.168.1.100:514
使用 systemd-remote-journal 集中收集日志:
# 日志服务器上
systemctl enable --now systemd-journal-remote.socket
# 客户端配置
cat > /etc/systemd/journal-upload.conf << 'EOF'
[Upload]
URL=https://logserver.example.com:19532
EOF
systemctl enable --now systemd-journal-upload.service
八、journalctl 命令速查表
查看与过滤
| 操作 | 命令 |
|---|---|
| 查看所有日志 | journalctl |
| 查看最新 N 条 | journalctl -n N |
| 实时跟踪 | journalctl -f |
| 反向查看 | journalctl -r |
| 按 Unit 过滤 | journalctl -u <unit> |
| 按优先级 | journalctl -p <level> |
| 按时间 | journalctl --since "..." --until "..." |
| 本次启动 | journalctl -b |
| 上次启动 | journalctl -b -1 |
| 内核日志 | journalctl -k |
输出格式
| 选项 | 说明 |
|---|---|
-o short | 默认短格式 |
-o short-iso | ISO 时间格式 |
-o verbose | 详细字段 |
-o json | JSON 格式 |
-o cat | 仅消息内容 |
存储管理
| 操作 | 命令 |
|---|---|
| 查看磁盘占用 | journalctl --disk-usage |
| 按大小清理 | journalctl --vacuum-size=100M |
| 按时间清理 | journalctl --vacuum-time=7d |
| 验证完整性 | journalctl --verify |
| 列出启动记录 | journalctl --list-boots |
九、生产场景
场景 1:排查服务崩溃
# 查看崩溃前后日志
journalctl -u myapp.service --since "2026-05-11 14:29" --until "2026-05-11 14:31"
# 只看错误
journalctl -u myapp.service -p err --since today
场景 2:安全审计
# 查看 sudo 使用记录
journalctl _COMM=sudo
# SSH 登录尝试
journalctl -u sshd.service | grep -E "(Accepted|Failed)"
# 导出安全日志
journalctl -u sshd.service --since "2026-05-01" -o json > audit-log.json
场景 3:磁盘空间不足
# 查看日志占用
journalctl --disk-usage
# 紧急清理
sudo journalctl --vacuum-time=1d
# 永久配置 /etc/systemd/journald.conf
# SystemMaxUse=500M
# MaxRetentionSec=1month
场景 4:日志分析
# 找出最活跃的服务(日志量前 10)
journalctl --since today -o json | \
jq -r '._SYSTEMD_UNIT // empty' | \
sort | uniq -c | sort -rn | head -10
# 查找 OOM 事件
journalctl -k | grep -i "out of memory"