<h1>Linux 日志管理与分析说明:journalctl、rsyslog 与 logrotate 实战</h1>
说明: 本文为配置思路与示例整理,不代表作者已在自己的服务器上逐项验证全部命令。执行涉及公网暴露、账户权限、数据删除或服务重启的操作前,请先备份,并结合官方文档与实际环境核验。
<p>服务器出了问题,第一反应是什么?查日志。但很多开发者面对满屏的日志输出却不知从何下手——systemd 的 journalctl 命令太长记不住,rsyslog 的配置看不懂,logrotate 转了半天还是磁盘满了。本文从实际运维场景出发,带你系统掌握 Linux 日志管理的三大核心工具。</p>
<!-- more -->
<h2>一、Linux 日志系统全景图</h2>
<p>现代 Linux 发行版(Ubuntu 16.04+、CentOS 7+、Debian 8+)的日志系统由三层组成:</p>
<table>
<thead>
<tr><th>层级</th><th>工具</th><th>职责</th></tr>
</thead>
<tbody>
<tr><td>收集层</td><td>systemd-journald</td><td>收集所有 systemd 服务的结构化日志</td></tr>
<tr><td>转发层</td><td>rsyslog</td><td>接收各类日志,按规则分发到文件/远程服务器</td></tr>
<tr><td>轮转层</td><td>logrotate</td><td>定时切割、压缩、清理旧日志,防止磁盘爆满</td></tr>
</tbody>
</table>
<p>三者协同工作,各司其职。理解它们的关系,是高效排查问题的前提。</p>
<h2>二、journalctl:systemd 日志瑞士军刀</h2>
<h3>2.1 基础查询</h3>
<p>journalctl 是与 systemd-journald 交互的命令行工具,日志默认存储在 <code>/var/log/journal/</code>(二进制格式)。</p>
<pre><code># 查看所有日志(从旧到新)
journalctl
查看最近 50 行
journalctl -n 50
实时跟踪日志(类似 tail -f)
journalctl -f
查看指定服务的日志
journalctl -u nginx
查看指定服务最近的日志
journalctl -u nginx -n 20
</code></pre>
<h3>2.2 按时间过滤</h3>
<p>这是最常用的场景——"昨天下午 3 点到 5 点之间发生了什么":</p>
<pre><code># 查看今天的日志
journalctl --since today
查看指定日期范围
journalctl --since "2026-05-12 14:00" --until "2026-05-12 18:00"
相对时间:最近 1 小时
journalctl --since "1 hour ago"
组合:指定服务 + 时间范围
journalctl -u docker --since "2026-05-12 00:00" --until "2026-05-13 00:00"
</code></pre>
<h3>2.3 高级过滤技巧</h3>
<pre><code># 按优先级过滤(0=emerg, 7=debug)
只看错误和更严重的日志
journalctl -p err
按优先级范围
journalctl -p warning..err
按 PID 过滤
journalctl _PID=1234
按进程名过滤
journalctl _COMM=nginx
按启动次数过滤(第 2 次启动的日志)
journalctl -b 2
查看本次启动以来的所有错误
journalctl -b -p err
</code></pre>
<h3>2.4 输出格式控制</h3>
<pre><code># JSON 格式输出(便于脚本处理)
journalctl -u nginx -o json | head -5
紧凑 JSON(一行一条)
journalctl -u nginx -o json-pretty
导出为可读格式
journalctl -u nginx --no-pager > /tmp/nginx-debug.log
</code></pre>
<h3>2.5 持久化配置</h3>
<p>默认情况下,journald 日志可能不持久化(重启后丢失)。编辑配置确保日志永久保存:</p>
<pre><code># 创建配置目录
sudo mkdir -p /etc/systemd/journald.conf.d
写入持久化配置
cat << 'EOF' | sudo tee /etc/systemd/journald.conf.d/persistent.conf
[Journal]
Storage=persistent
SystemMaxUse=500M
MaxRetentionSec=3month
Compress=yes
EOF
重启 journald
sudo systemctl restart systemd-journald
验证配置
journalctl --disk-usage
</code></pre>
<h2>三、rsyslog:灵活的日志分发引擎</h2>
<h3>3.1 理解 rsyslog 的作用</h3>
<p>虽然 journald 已经很强大,但 rsyslog 在以下场景仍然不可替代:</p>
<ul>
<li>将多台服务器的日志汇聚到一台中心服务器</li>
<li>将特定程序的日志写入独立文件(如单独记录 Nginx 访问日志)</li>
<li>将日志发送到远程日志服务器做集中管理</li>
<li>兼容传统应用(直接写 <code>/var/log/</code> 下文件的程序)</li>
</ul>
<h3>3.2 核心配置</h3>
<p>主配置文件:<code>/etc/rsyslog.conf</code>,模块化配置放在 <code>/etc/rsyslog.d/</code> 目录下。</p>
<pre><code># /etc/rsyslog.d/50-default.conf 关键配置解读
日志分类:facility.priority action
facility: auth, cron, daemon, kern, mail, user, local0-7 等
priority: emerg, alert, crit, err, warning, notice, info, debug
Nginx 日志独立输出
if $programname == 'nginx' then /var/log/nginx/app.log
& stop # stop 表示处理完这条规则后不再往下走
SSH 登录日志单独记录
if $programname == 'sshd' then /var/log/ssh.log
自定义应用日志(local0-facility)
local0.* /var/log/myapp.log
</code></pre>
<h3>3.3 远程日志传输</h3>
<p>将日志发送到远程服务器(sender 端配置):</p>
<pre><code># /etc/rsyslog.d/remote.conf
使用 TCP 传输(可靠)
. @@log-server.example.com:514
使用 UDP 传输(快速但可能丢日志)
. @log-server.example.com:514
启用 TLS 加密传输(推荐)
module(load="imtcp")
input(type="imtcp" port="514")
</code></pre>
<p>接收端配置:</p>
<pre><code># 在 log-server 上的 /etc/rsyslog.conf
module(load="imtcp")
input(type="imtcp" port="514")
按来源主机分目录存储
$template RemoteLogs,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
. ?RemoteLogs
</code></pre>
<h3>3.4 测试与验证</h3>
<pre><code># 修改配置后重启
sudo systemctl restart rsyslog
测试日志转发
logger -p local0.info "Test message from $(hostname)"
验证日志是否写入
tail -f /var/log/myapp.log
检查 rsyslog 状态
sudo systemctl status rsyslog
</code></pre>
<h2>四、logrotate:日志轮转防爆盘</h2>
<h3>4.1 为什么需要日志轮转</h3>
<p>一个繁忙的 Nginx 服务器,access.log 每天可能增长几百 MB。如果不做轮转,几个月后磁盘就会被撑满。logrotate 通过 cron 每天自动运行,负责切割、压缩、清理日志文件。</p>
<h3>4.2 配置语法详解</h3>
<pre><code># /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily # 每天轮转(weekly/monthly/rotate N)
missingok # 日志文件不存在时不报错
rotate 14 # 保留 14 个轮转文件(即 14 天)
compress # 用 gzip 压缩旧日志
delaycompress # 延迟一次再压缩(当前轮转的不压缩)
notifempty # 空文件不轮转
create 0644 www-data www-data # 轮转后创建新文件,指定权限和所有者
sharedscripts # 多个日志文件只执行一次脚本
postrotate # 轮转后执行的命令
# 通知应用重新打开日志文件(很多程序需要这一步)
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}
Nginx 默认配置示例
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}
</code></pre>
<h3>4.3 实用配置模式</h3>
<pre><code># 按文件大小轮转(超过 100MB 就切割)
/var/log/bigapp.log {
size 100M
rotate 5
compress
copytruncate # 先复制再清空原文件(适合不能重启的进程)
}
按小时轮转(高流量场景)
/var/log/access.log {
hourly
rotate 48
compress
dateext # 用日期作为后缀而非数字
dateformat -%Y%m%d%H
missingok
}
只压缩超过 1 周的旧日志
/var/log/app.log {
daily
rotate 30
compress
delaycompress
oldestfirst # 先删除最旧的
}
</code></pre>
<h3>4.4 手动测试与调试</h3>
<pre><code># 语法检查(不实际执行,只检查配置是否正确)
sudo logrotate -d /etc/logrotate.d/myapp
强制执行轮转(即使还没到时间)
sudo logrotate -f /etc/logrotate.d/myapp
查看 logrotate 状态文件
cat /var/lib/logrotate/status
查看 logrotate 的执行日志
cat /var/log/logrotate.log
</code></pre>
<h2>五、实战场景:排查 Nginx 502 Bad Gateway</h2>
<p>把三个工具组合起来,还原一个真实的排查流程:</p>
<h3>场景描述</h3>
<p>网站突然出现 502 Bad Gateway,持续时间约 5 分钟后自动恢复。</p>
<h3>排查步骤</h3>
<pre><code># 第一步:确认时间范围
用户报告时间约 14:30-14:35,扩大到 14:25-14:40
第二步:查 Nginx 错误日志
journalctl -u nginx --since "2026-05-13 14:25" --until "2026-05-13 14:40" -p err
发现:connect() failed (111: Connection refused) while connecting to upstream
第三步:查后端应用状态
journalctl -u myapp --since "2026-05-13 14:25" --until "2026-05-13 14:40"
发现:应用在 14:28 被 OOM Killer 杀掉了
第四步:查系统级日志确认 OOM
journalctl -k --since "2026-05-13 14:25" --until "2026-05-13 14:40"
-k 只看内核日志,确认了 Out of memory: Kill process
第五步:分析为什么 OOM
journalctl -u myapp -p warning | grep -i "memory" | tail -20
发现应用内存持续增长,疑似内存泄漏
第六步:查看历史是否频繁发生
journalctl -u myapp -p err --since "2026-05-01" --no-pager | wc -l
发现这个月已经 OOM 了 7 次
结论:应用存在内存泄漏,需要修复代码中的缓存问题
</code></pre>
<h3>预防措施</h3>
<pre><code># 配置 systemd 服务的内存限制
/etc/systemd/system/myapp.service.d/limits.conf
[Service]
MemoryMax=512M
MemoryHigh=384M
Restart=on-failure
RestartSec=5
配置日志自动告警(当错误率过高时通知)
在 /etc/logrotate.d/myapp 的 postrotate 中加入告警脚本
postrotate
ERROR_COUNT=ERROR_COUNT" -gt 10 ]; then
echo "$(date): $ERROR_COUNT errors in myapp in the last hour" >> /var/log/alerts.log
fi
endscript
</code></pre>
<h2>六、常用速查表</h2>
<pre><code># ===== journalctl 速查 =====
journalctl -u SERVICE # 查看某服务日志
journalctl -p err # 只看错误
journalctl --since "1h ago" # 最近 1 小时
journalctl -f # 实时跟踪
journalctl -b # 本次启动日志
journalctl -b -1 # 上次启动日志
journalctl --disk-usage # 日志占用空间
journalctl --vacuum-size=200M # 清理日志到 200MB
===== rsyslog 速查 =====
sudo systemctl restart rsyslog # 重启 rsyslog
sudo rsyslogd -N1 # 检查配置语法
logger "test message" # 手动写入测试日志
===== logrotate 速查 =====
sudo logrotate -d /etc/logrotate.d/FILE # 调试模式
sudo logrotate -f /etc/logrotate.d/FILE # 强制轮转
cat /var/lib/logrotate/status # 查看轮转状态
</code></pre>
<h2>总结</h2>
<p>Linux 日志管理的三大工具各有分工:journalctl 负责结构化查询和实时跟踪,rsyslog 负责日志分发和远程传输,logrotate 负责定时轮转和磁盘空间管理。掌握这三者的配合使用,能让你在服务器故障排查时事半功倍。</p>
<p>记住排查日志的黄金法则:先确定时间范围,再按服务/优先级过滤,最后结合系统日志交叉验证。大多数问题都能在这几步内找到根源。</p>
评论
游客无需注册即可评论。
你提交的昵称、邮箱、网址和评论内容会保存在服务端,用于展示评论身份、接收回复及必要的安全审计。
浏览器会本地保存已填游客信息和评论草稿,方便下次免填。
回复提醒会通过站内消息和邮件通知。