Почему строки журнала, написанные Monolog, не путаются/перепутываются, когда два экземпляра скрипта одновременно записывают в журнал?

При использовании Monolog с StreamHandler это нормальная ситуация, когда несколько экземпляров скрипта PHP будут параллельно записывать в один и тот же файл журнала.

(например, в моем приложении Symfony, когда несколько пользователей открывают «страницу входа» одновременно, это приведет к запуску нескольких экземпляров сценария моего приложения (app.php), и, таким образом, два экземпляра Monolog StreamHandler будут записываться в один и тот же app/logs/prod.log.)

Почему, несмотря на одновременную запись в файл, каждая строка журнала не разрывается посередине и не перепутывается? Почему ситуация ниже никогда не происходит:

  • instance1 StreamHanler записал только половину строки журнала,
  • instance2 StreamHanler записал первую половину
  • экземпляр1 записал вторую половину строки журнала
  • instance2 записал вторую половину строки журнала
  • теперь наш лог-файл в беспорядке, потому что перепутаны две строки.

Я попытался просмотреть исходный код StreamHanler https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/StreamHandler.php#L93

Но я не вижу никакого надлежащего контроля параллелизма, есть flock(), но он, кажется, отключен (->useLocking=false) в конфигурации по умолчанию (Symfony), и кажется, что журналы без него в порядке...

    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);
    }

Но почему журналы волшебным образом в порядке?


person Dimitry K    schedule 27.03.2015    source источник
comment
Вы нашли ответ?   -  person Progrock    schedule 16.12.2020
comment
@Progrock я этого не делал, но, насколько я понимаю, fwrites () записывает в файловый буфер (кэш) ОС, который очищается ОС. Таким образом, даже если несколько процессов выполняют fwrite() в одном и том же файле, каждый fwrite() АТОМИЧЕСКИ записывает в кеш ОС, и вся строка журнала будет записана целиком. Затем ОС очищает свой буфер (состоящий из полных строк журнала). И буфер ОС всегда содержит полные строки, и сброс на диск будет гарантирован. Когда строки журнала записываются, например. слово за словом с несколькими fwrite() только тогда они будут искажены. Даже не очень длинные строки (больше буфера ОС) не могут привести к повреждению (если не сбой жесткого диска)   -  person Dimitry K    schedule 25.12.2020
comment
Похоже, что описанное выше поведение выполняется только в том случае, если файл открыт в режиме APPEND stackoverflow.com/a/35258623/1168382   -  person Dimitry K    schedule 25.12.2020


Ответы (1)


Когда я использую ведение журнала, я ожидаю, что основные компоненты будут работать правильно. Это не какой-то контейнер, который вам нужен для обеспечения параллельного доступа.

Я читал, что основные потоковые операционные системы используют потокобезопасные вызовы ввода-вывода, которые также не могут быть прерваны, и есть не потокобезопасные вызовы.

Вы можете прочитать здесь, но, на мой взгляд, отмеченный ответ вообще неверен: Is fwrite atomic?

Другими словами, у меня никогда не было сломанных журналов. Это как INSERT в базе данных. Либо вставлена ​​строка, либо нет.

person Aitch    schedule 27.03.2015