diff --git a/src/Monolog/Handler/StreamHandler.php b/src/Monolog/Handler/StreamHandler.php index 8d4e3f5d..6e1210cb 100644 --- a/src/Monolog/Handler/StreamHandler.php +++ b/src/Monolog/Handler/StreamHandler.php @@ -38,6 +38,7 @@ class StreamHandler extends AbstractProcessingHandler /** @var true|null */ private bool|null $dirCreated = null; private bool $retrying = false; + private int|null $inodeUrl = null; /** * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write @@ -133,6 +134,13 @@ class StreamHandler extends AbstractProcessingHandler */ protected function write(LogRecord $record): void { + if ($this->hasUrlInodeWasChanged()) { + $this->close(); + $this->write($record); + + return; + } + if (!\is_resource($this->stream)) { $url = $this->url; if (null === $url || '' === $url) { @@ -157,6 +165,7 @@ class StreamHandler extends AbstractProcessingHandler } stream_set_chunk_size($stream, $this->streamChunkSize); $this->stream = $stream; + $this->inodeUrl = $this->getInodeFromUrl(); } $stream = $this->stream; @@ -246,4 +255,26 @@ class StreamHandler extends AbstractProcessingHandler } $this->dirCreated = true; } + + private function getInodeFromUrl(): ?int + { + if ($this->url === null || $this->url === 'php://memory') { + return null; + } + + $inode = @fileinode($this->url); + + return $inode === false ? null : $inode; + } + + private function hasUrlInodeWasChanged(): bool + { + if ($this->inodeUrl === null || $this->retrying || $this->inodeUrl === $this->getInodeFromUrl()) { + return false; + } + + $this->retrying = true; + + return true; + } } diff --git a/tests/Monolog/Handler/StreamHandlerTest.php b/tests/Monolog/Handler/StreamHandlerTest.php index bdce21fd..e2241234 100644 --- a/tests/Monolog/Handler/StreamHandlerTest.php +++ b/tests/Monolog/Handler/StreamHandlerTest.php @@ -365,4 +365,16 @@ The exception occurred while attempting to log: test'); ini_set('memory_limit', $previousValue); } } + + public function testReopensFileIfInodeChanges() + { + $filename = __DIR__ . '/test.log'; + $handler = new StreamHandler($filename); + $handler->setFormatter($this->getIdentityFormatter()); + $handler->handle($this->getRecord(Level::Warning, 'test1')); + @unlink($filename); + $handler->handle($this->getRecord(Level::Warning, 'test2')); + $data = @file_get_contents($filename); + $this->assertEquals('test2', $data); + } }