Monolog don';当两个脚本实例同时写入日志时,不要搞砸/混淆


How come log lines written by Monolog don't get messed/mixed up when two script instances are writing to log concurrently?

将Monolog与StreamHandler一起使用时,PHP脚本的多个实例并行写入同一日志文件是正常情况。

(例如,在我的Symfony应用程序中,当多个用户同时打开"登录页"时,会导致我的应用程序脚本(app.php)的多个实例运行,因此Monolog StreamHandler的两个实例将写入同一个app/logs/prod.log。)

为什么尽管同时写入文件,但每个日志行都不会在中间中断和混乱?为什么以下情况从未发生:

  • StreamHanler的instance1只写入了日志行的一半
  • StreamHanler的instance2编写了它的前半部分
  • instance1写入日志行的后半部分
  • instance2写入日志行的后半部分
  • 现在我们的日志文件一团糟,因为两行代码混在一起了

我试着查看StreamHanler的源代码https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/StreamHandler.php#L93

但我看不到任何适当的并发控制,有一个flock(),但在默认(Symfony)配置中它似乎被禁用了(->useLocking=false),没有它日志似乎也很好…

    if ($this->useLocking) {
        // ignoring errors here, there's not much we can do about them
        flock($this->stream, LOCK_EX);
    }
    fwrite($this->stream, (string) $record['formatted']);
    if ($this->useLocking) {
        flock($this->stream, LOCK_UN);
    }

但为什么原木神奇地好呢?

当我使用日志记录时,我希望底层组件能够正常工作。它不是任何必须确保并发访问的容器。

我读过,主流操作系统使用线程安全的io调用,这些调用也是不可中断的,也有非线程安全的调用。

你可以在这里阅读,但在我看来,标记的答案根本不正确:fwrite是原子的吗?

换言之,我从未有过任何破损的原木。这就像数据库中的INSERT。是否插入了行。