保证在日志文件不再被写入后重命名日志文件

保证在日志文件不再被写入后重命名日志文件

我有以下设置。

在远程机器上,我有一个持续运行的进程,它订阅一些数据并将其写入 stdout(让我们将该进程称为订阅者)。我从 .sh 脚本调用订阅者,该脚本将 stdout 重定向到包含名称日期的文件中,我们将其称为日志文件。总的来说,我想要实现的是将这些日志文件分成不同的日期,这样我就可以将它们从远程机器带到本地。

有一件事与我的情况有关,导致我熟悉的解决方案无法工作:日志文件包含快照数据和增量流。这意味着我不能只对日志文件进行日志轮转,因为下一个日志文件的开头会缺少快照。我现在处理这个问题的方法是手动停止订阅者,然后从 .sh 脚本重新启动它。.sh 脚本将标准输出重定向到下一个日期的日志文件。在重新启动之间丢失几秒钟的数据对我来说没有问题。有问题的是日志文件缺少其初始快照。

所以我的问题是:自动化这个手动过程的正确方法是什么?

我有一个我不喜欢的部分解决方案。

  • 每天在特定时间从 crontab 调用一个新的 .sh 脚本
  • 然后,该脚本将按名称终止所有进程(即订阅者)
  • 重新启动订阅服务器,stdout 指向新的日志文件,但不是命名它,而是命名.log.log.part,灵感来自这个答案
  • 那么我必须找出如何保证当订阅者死亡时,.log.part日志文件被重命名为.log,这表明该日志文件可以移出
  • 然后从本地机器运行 rsync 来传输所有.log文件。

即使我找到了如何完成最后一步,我也不喜欢这个解决方案,因为我从未见过像这样在 cronjobs 之上构建的强大管道。

因此,如果有人知道一种可靠的方法来做到这一点,那是什么呢?如果没有,我如何保证当订阅者死亡时.log.part文件被重命名?.log

谢谢

答案1

您当前的 cron 脚本可能看起来像这样:

setsid subscriber > subscriber.date.log &

您希望让 shell 等待订阅者退出,然后重命名其输出。类似下面的代码可以实现:

log_date_str=`date ...`

watcher()
{
        subscriber > subscriber.${log_date_str}.log.part
        mv subscriber.${log_date_str}.log.part subscriber.${log_date_str}.log
}

killall subscriber
setsid watcher &

由于 watcher 是在后台启动的,因此它位于一个单独的 shell 进程中。父 shell 启动 shell 函数然后退出。watch 函数在其自己的 shell 进程中启动订阅者,然后等待它完成。完成后,它会执行重命名。

有几个问题:

如果订阅者像守护进程一样分叉到后台,并且没有被 shell 脚本置于后台,那么您需要弄清楚如何阻止它这样做(-d 很常见)。这是一个不太可能的陷阱,因为输出到 stdout 并分叉本身会很奇怪。

其次,如果您的 shell 没有内置 setsid,您将必须将 watch 拆分为其自己的 shell 脚本并调用该脚本而不是该函数。

我建议使用 pstree 来查看父子关系。

另外,请确保您没有在脚本中执行 set -e(或者在观察器中将其关闭),否则当订阅者因错误退出时,mv 将不会完成。

相关内容