From c48c642b9af1f4e57fdfa28af41696cc6adb14f2 Mon Sep 17 00:00:00 2001 From: cracksalad Date: Fri, 12 Apr 2024 17:37:06 +0200 Subject: [PATCH] [#1878] User definable duplication for DeduplicationHandler (#1879) --- src/Monolog/Handler/DeduplicationHandler.php | 48 ++++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/src/Monolog/Handler/DeduplicationHandler.php b/src/Monolog/Handler/DeduplicationHandler.php index b8ec90099..0ef2734f4 100644 --- a/src/Monolog/Handler/DeduplicationHandler.php +++ b/src/Monolog/Handler/DeduplicationHandler.php @@ -43,8 +43,7 @@ class DeduplicationHandler extends BufferHandler protected Level $deduplicationLevel; protected int $time; - - private bool $gc = false; + protected bool $gc = false; /** * @param HandlerInterface $handler Handler. @@ -70,13 +69,24 @@ public function flush(): void return; } + $store = null; + + if (file_exists($this->deduplicationStore)) { + $store = file($this->deduplicationStore, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + } + $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 = []; + } + $store[] = $line; } } } @@ -93,20 +103,15 @@ public function flush(): void } } - private function isDuplicate(LogRecord $record): bool + /** + * 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 { - 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); + $yesterday = time() - 86400; for ($i = count($store) - 1; $i >= 0; $i--) { list($timestamp, $level, $message) = explode(':', $store[$i], 3); @@ -123,6 +128,14 @@ private function isDuplicate(LogRecord $record): bool 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 { if (!file_exists($this->deduplicationStore)) { @@ -158,9 +171,4 @@ private function collectLogs(): void $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); - } }