将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
。是否插入了行。