From 249373002afded5594eb671028eb0f62deeee014 Mon Sep 17 00:00:00 2001 From: Andreas Wahlen Date: Fri, 5 Apr 2024 18:37:27 +0200 Subject: [PATCH 1/4] Individualizable DeduplicationHandler --- src/Monolog/Handler/DeduplicationHandler.php | 63 +++++++++++--------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index b8ec90099..b942a2866 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -44,8 +44,6 @@ class DeduplicationHandler extends BufferHandler protected int $time; - private bool $gc = false; - /** * @param HandlerInterface $handler Handler. * @param string|null $deduplicationStore The file/path where the deduplication log should be kept @@ -70,13 +68,33 @@ public function flush(): void return; } + $gc = false; + $store = null; + + if (file_exists($this->deduplicationStore)) { + $store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + if (is_array($store)) { + $yesterday = time() - 86400; + for ($i = 0; $i < count($store); $i++) { + if (substr($store[$i], 0, 10) < $yesterday) { + $gc = true; + break; + } + } + } + } + $passthru = null; foreach ($this->buffer as $record) { if ($record->level->value >= $this->deduplicationLevel->value) { - $passthru = $passthru === true || !$this->isDuplicate($record); + $passthru = $passthru === true || !is_array($store) || !$this->isDuplicate($store, $record); if ($passthru) { - $this->appendRecord($record); + $line = $this->buildDeduplicationStoreEntry($record); + file_put_contents($this->deduplicationStore, $line . "\n", FILE_APPEND); + if (is_array($store)) { + $store[] = $line; + } } } } @@ -88,23 +106,16 @@ public function flush(): void $this->clear(); - if ($this->gc) { + if ($gc) { $this->collectLogs(); } } - private function isDuplicate(LogRecord $record): bool + /** + * @param string[] $store The deduplication store + */ + protected function isDuplicate(array $store, LogRecord $record): bool { - if (!file_exists($this->deduplicationStore)) { - return false; - } - - $store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - if (!is_array($store)) { - return false; - } - - $yesterday = time() - 86400; $timestampValidity = $record->datetime->getTimestamp() - $this->time; $expectedMessage = preg_replace('{[\r\n].*}', '', $record->message); @@ -113,15 +124,18 @@ private function isDuplicate(LogRecord $record): bool if ($level === $record->level->getName() && $message === $expectedMessage && $timestamp > $timestampValidity) { return true; - } - - if ($timestamp < $yesterday) { - $this->gc = true; - } + } } return false; } + + /** + * @return string The given record serialized as a single line of text + */ + protected function buildDeduplicationStoreEntry(LogRecord $record): string { + return $record->datetime->getTimestamp() . ':' . $record->level->getName() . ':' . preg_replace('{[\r\n].*}', '', $record->message); + } private function collectLogs(): void { @@ -155,12 +169,5 @@ private function collectLogs(): void flock($handle, LOCK_UN); fclose($handle); - - $this->gc = false; - } - - private function appendRecord(LogRecord $record): void - { - file_put_contents($this->deduplicationStore, $record->datetime->getTimestamp() . ':' . $record->level->getName() . ':' . preg_replace('{[\r\n].*}', '', $record->message) . "\n", FILE_APPEND); } } From d2b2a67ba90234982af234b328ba7c4433a93c10 Mon Sep 17 00:00:00 2001 From: Andreas Wahlen Date: Sun, 7 Apr 2024 14:43:09 +0200 Subject: [PATCH 2/4] Fix coding style issues --- src/Monolog/Handler/DeduplicationHandler.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index b942a2866..d9063f809 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -70,7 +70,7 @@ public function flush(): void $gc = false; $store = null; - + if (file_exists($this->deduplicationStore)) { $store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); if (is_array($store)) { @@ -83,7 +83,7 @@ public function flush(): void } } } - + $passthru = null; foreach ($this->buffer as $record) { @@ -129,11 +129,12 @@ protected function isDuplicate(array $store, LogRecord $record): bool return false; } - + /** * @return string The given record serialized as a single line of text */ - protected function buildDeduplicationStoreEntry(LogRecord $record): string { + protected function buildDeduplicationStoreEntry(LogRecord $record): string + { return $record->datetime->getTimestamp() . ':' . $record->level->getName() . ':' . preg_replace('{[\r\n].*}', '', $record->message); } From 17e3917ae5bdf125c7f8c8e30bc481a0f76ba513 Mon Sep 17 00:00:00 2001 From: Andreas Wahlen Date: Fri, 12 Apr 2024 12:45:01 +0200 Subject: [PATCH 3/4] Move GC trigger back to isDuplicate() --- src/Monolog/Handler/DeduplicationHandler.php | 23 ++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index d9063f809..fc9dc523a 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -43,6 +43,8 @@ class DeduplicationHandler extends BufferHandler protected Level $deduplicationLevel; protected int $time; + + protected bool $gc = false; /** * @param HandlerInterface $handler Handler. @@ -73,15 +75,6 @@ public function flush(): void if (file_exists($this->deduplicationStore)) { $store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - if (is_array($store)) { - $yesterday = time() - 86400; - for ($i = 0; $i < count($store); $i++) { - if (substr($store[$i], 0, 10) < $yesterday) { - $gc = true; - break; - } - } - } } $passthru = null; @@ -106,25 +99,31 @@ public function flush(): void $this->clear(); - if ($gc) { + if ($this->gc) { $this->collectLogs(); } } /** + * If there is a store entry older than e.g. a day, this method should set `$this->gc` to `true` to trigger garbage collection. * @param string[] $store The deduplication store */ protected function isDuplicate(array $store, LogRecord $record): bool { $timestampValidity = $record->datetime->getTimestamp() - $this->time; $expectedMessage = preg_replace('{[\r\n].*}', '', $record->message); + $yesterday = time() - 86400; for ($i = count($store) - 1; $i >= 0; $i--) { list($timestamp, $level, $message) = explode(':', $store[$i], 3); if ($level === $record->level->getName() && $message === $expectedMessage && $timestamp > $timestampValidity) { return true; - } + } + + if ($timestamp < $yesterday) { + $this->gc = true; + } } return false; @@ -170,5 +169,7 @@ private function collectLogs(): void flock($handle, LOCK_UN); fclose($handle); + + $this->gc = false; } } From d9e2a9d80e12a016ad0097b70c188a870a0a2064 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 12 Apr 2024 14:27:31 +0200 Subject: [PATCH 4/4] Apply suggestions from code review --- src/Monolog/Handler/DeduplicationHandler.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index fc9dc523a..0ef2734f4 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -43,7 +43,6 @@ class DeduplicationHandler extends BufferHandler protected Level $deduplicationLevel; protected int $time; - protected bool $gc = false; /** @@ -70,7 +69,6 @@ public function flush(): void return; } - $gc = false; $store = null; if (file_exists($this->deduplicationStore)) { @@ -85,9 +83,10 @@ public function flush(): void if ($passthru) { $line = $this->buildDeduplicationStoreEntry($record); file_put_contents($this->deduplicationStore, $line . "\n", FILE_APPEND); - if (is_array($store)) { - $store[] = $line; + if (!is_array($store)) { + $store = []; } + $store[] = $line; } } }