monolog: Issue with Logging to stdout in Laravel 10.21 using Monolog v3 EXCEPTION#Cannot log request: fwrite(): Write of 378 bytes failed with errno=32 Broken pipe

Monolog version 3

Hello,

I’m currently working with Laravel 10.21 and have encountered an issue when attempting to write logs to stdout using Monolog version 3. My configuration is as follows:

'stdout' => [
    'driver' => 'monolog',
    'handler' => StreamHandler::class,
    'formatter' => '\Monolog\Formatter\JsonFormatter',
    'with' => [
        'stream' => 'php://stdout',
    ],
],

However, this setup results in an exception:

Exception: /var/www/html/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php::162 -> EXCEPTION#Cannot log request: fwrite(): Write of 378 bytes failed with errno=32 Broken pipe

I noticed a similar issue previously reported as #1634, but it seems the problem persists. Any guidance or suggestions to resolve this would be greatly appreciated.

Thank you for your support.

Best regards,

About this issue

  • Original URL
  • State: open
  • Created 7 months ago
  • Reactions: 1
  • Comments: 32 (9 by maintainers)

Commits related to this issue

Most upvoted comments

It is because of this:

https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/StreamHandler.php#L118

is_resource is not enough to handle writing to an already closed socket

[EDITED - the first solution was not the proper one]

The library should handle recreation of $this->stream on fwrite() error here: https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/StreamHandler.php#L149

As the only way to tell if the pipe is broken is basically when trying to write to it.

Also assuming fwrite will always succeed is a bit overoptimistic: https://github.com/Seldaek/monolog/blob/main/src/Monolog/Handler/StreamHandler.php#L160C24-L160C24

Sample pseudocode for this (as fwrite does not have to write everything in single call we could also check number of bytes written):

    protected function streamWrite($stream, LogRecord $record): bool
    {
        $result = fwrite($stream, (string) $record->formatted) === false
        if ($result === false)
            return false
       if ($result === length($record))
            return true;
       return false;
    }

Although locally the fwrite should be usually able to write all the bytes to the stdout (although I would not be doing the same on network sockets).

Hello We’ve been running into the same problem in our testing and develop environments We use Monolog 2.9.2 on Magento 2.4.6 and PHP 8.1 We encountered the problem when trying to write the logs to both stdout and stderr Unfortunately the fclose2 patch didn’t help much The only thing I found that fixed the problem is this: file src/Monolog/Handler/StreamHandler.php

protected function streamWrite($stream, array $record): void
{
    try {
        fwrite($stream, (string) $record['formatted']);
    } catch(\Exception $e) {
        fdatasync($stream);
        fwrite($stream, (string) $record['formatted']);
    }
}

For some reason executing fdatasync before retrying fwrite fixed the problem Note that fsync also did the job I don’t really know why this fixed the problem or if this is the cleanest way to do it but hopefully it will help you patch the module

@TheLevti that’s why I said to put "dev-fclose3 as 3.99" as require so that composer aliases it and it passes the ^3.0 requires other packages may have on it.

We have the same issue in production, occured after upgrade to PHP 8.2 and Monolog 3

EDIT: so far it seems that file descriptors build up until reaching the limit of the kernel, preventing any new fwrite. Rebooting our servers fix the issue for a while. It seems like the stream isn’t closed properly, or at least not in all cases. I’ve noticed that it should be done during the __destruct() phase of the handler, but is there some edge cases where it isn’t called? (php-fpm process crash or something else)

See also comments on #1634 - I’m still waiting for a way to narrow this down.