同步失败日志去哪了?别再在系统日志里盲目查找
先了解几个关键点,避免你一头扎进系统日志中翻找半天,却毫无收获。
默认情况下,rsync、unison、lftp 或者 inotifywait + scp 这些同步工具,根本不会将失败重试的细节写入系统日志——无论是 /var/log/messages 还是 journalctl,它们都不会记录这些信息。错误和重试行为仅输出到 stderr 或你指定的日志文件中。换句话说,如果没有显式配置,就不会写入磁盘。
因此,不要指望 grep "retry" /var/log/syslog 能返回结果,那多半是空的。真正需要查找的是同步命令自身产生的日志路径,或者其 stdout/stderr 的捕获位置。
如果一开始就卡住了,请先确认以下几点:
- 使用的是哪个同步工具?
rsync最为常见,但lftp的重试机制完全不同。 - 启动命令是否包含了
--log-file=、-o LogLevel=DEBUG、-v --debug这类参数? - 如果通过 systemd 启动,请检查
systemctl status sync-unit和journalctl -u sync-unit -n 100。但注意:只有将 stdout/stderr 重定向到 journal 的服务,才会留下重试记录。
rsync 的失败重试日志,需要手动开启
rsync 本身默认不会重试——它失败就立即退出,干脆利落。所谓的“重试”,其实是外层脚本或 systemd Restart=on-failure 在背后悄悄兜底。要查看每次失败与重试的完整上下文,必须让它将所有输出都记录下来:
- 添加
-v --log-file=/path/to/rsync.log:记录传输过程、跳过原因、IO 错误等。但注意,它不会出现“第几次重试”这样的字样。 - 添加
--debug=all(仅调试用):输出 socket 连接尝试、超时、重连动作,但日志极其冗长,且仅输出到终端,需要配合2>&1 | tee才能捕获。 - 真正的重试逻辑在 wrapper 脚本里?那么就需要查看脚本中是否有
echo "$(date) - retry #${i}" >> /var/log/sync-retry.log这类显式记录。
以下是一个最小可行的脚本示例,带有重试计数的功能:
for i in {1..3}; do
if rsync -a vz --delete user@host:/remote/ /local/ 2>>/var/log/rsync-full.log; then
echo "$(date) - success after $i attempts" >> /var/log/sync-summary.log
exit 0
else
echo "$(date) - failed attempt #$i" >> /var/log/sync-summary.log
sleep 5
fi
done
journalctl 查不到重试日志?检查 systemd 服务配置
如果你将同步任务配置为 systemd service,但 journalctl -u my-rsync.service 中看不到重试信息,很可能是因为以下几个原因:
- 没有设置
StandardError=journal(默认是inherit,继承父进程 stderr,常常指向 /dev/null) - 没有添加
Restart=on-failure或RestartSec=10,根本未触发重试 - 重试时,脚本每次都使用
> /tmp/log而非>>,导致旧日志被覆盖
正确的 service 片段应包含以下配置:
[Service] Type=oneshot ExecStart=/usr/local/bin/sync-wrapper.sh Restart=on-failure RestartSec=30 StandardOutput=journal StandardError=journal
排查时,优先检查这三个位置,避免大海捞针
不要在整个全局日志中反复翻找,请按顺序排查:
- 同步命令本身是否写入了日志文件?查看启动参数中的
--log-file、-o logfile=、2>/var/log/xxx.err。 - 执行该命令的用户 home 目录下,是否存在临时日志?例如
~/.rsync-log、~/sync-errors.log。 - 如果是 cron 触发,检查
MAILTO是否开启。失败时,邮件中通常会包含 stderr 内容。
真正的重试细节几乎从不进入 /var/log/ 目录树,除非你明确将其导向那里。最容易忽略的一点是:你误以为工具自带重试,其实只是 shell 循环或 systemd 在兜底——而那个兜底逻辑的日志,需要你自己来记录。
