diff --git a/src/Monolog/Handler/AbstractHandler.php b/src/Monolog/Handler/AbstractHandler.php index da5bbc05..c9405bfb 100644 --- a/src/Monolog/Handler/AbstractHandler.php +++ b/src/Monolog/Handler/AbstractHandler.php @@ -92,6 +92,5 @@ abstract class AbstractHandler extends Handler implements ResettableInterface public function reset() { - $this->close(); } } diff --git a/src/Monolog/Handler/AbstractProcessingHandler.php b/src/Monolog/Handler/AbstractProcessingHandler.php index b9da8985..1100260c 100644 --- a/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/src/Monolog/Handler/AbstractProcessingHandler.php @@ -11,10 +11,8 @@ namespace Monolog\Handler; -use Monolog\ResettableInterface; - /** - * Base Handler class providing the Handler structure + * Base Handler class providing the Handler structure, including processors and formatters * * Classes extending it should (in most cases) only implement write($record) * @@ -55,10 +53,6 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc { parent::reset(); - foreach ($this->processors as $processor) { - if ($processor instanceof ResettableInterface) { - $processor->reset(); - } - } + $this->resetProcessors(); } } diff --git a/src/Monolog/Handler/BrowserConsoleHandler.php b/src/Monolog/Handler/BrowserConsoleHandler.php index dc12b653..620e2e67 100755 --- a/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/src/Monolog/Handler/BrowserConsoleHandler.php @@ -13,7 +13,6 @@ namespace Monolog\Handler; use Monolog\Formatter\LineFormatter; use Monolog\Formatter\FormatterInterface; -use Monolog\ResettableInterface; /** * Handler sending logs to browser's javascript console with no browser extension required @@ -75,6 +74,11 @@ class BrowserConsoleHandler extends AbstractProcessingHandler } } + public function close() + { + self::resetStatic(); + } + public function reset() { parent::reset(); diff --git a/src/Monolog/Handler/BufferHandler.php b/src/Monolog/Handler/BufferHandler.php index 3ac7f551..a26430fe 100644 --- a/src/Monolog/Handler/BufferHandler.php +++ b/src/Monolog/Handler/BufferHandler.php @@ -105,6 +105,8 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa public function close(): void { $this->flush(); + + $this->handler->close(); } /** @@ -118,8 +120,12 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa public function reset() { + $this->flush(); + parent::reset(); + $this->resetProcessors(); + if ($this->handler instanceof ResettableInterface) { $this->handler->reset(); } diff --git a/src/Monolog/Handler/FilterHandler.php b/src/Monolog/Handler/FilterHandler.php index 886178de..d4517f29 100644 --- a/src/Monolog/Handler/FilterHandler.php +++ b/src/Monolog/Handler/FilterHandler.php @@ -12,6 +12,7 @@ namespace Monolog\Handler; use Monolog\Logger; +use Monolog\ResettableInterface; /** * Simple handler wrapper that filters records based on a list of levels @@ -21,7 +22,7 @@ use Monolog\Logger; * @author Hennadiy Verkh * @author Jordi Boggiano */ -class FilterHandler extends Handler implements ProcessableHandlerInterface +class FilterHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface { use ProcessableHandlerTrait; @@ -137,4 +138,9 @@ class FilterHandler extends Handler implements ProcessableHandlerInterface $this->handler->handleBatch($filtered); } + + public function reset() + { + $this->resetProcessors(); + } } diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 90727a04..f7c5fd9c 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -131,25 +131,16 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa */ public function close(): void { - if (null !== $this->passthruLevel) { - $level = $this->passthruLevel; - $this->buffer = array_filter($this->buffer, function ($record) use ($level) { - return $record['level'] >= $level; - }); - if (count($this->buffer) > 0) { - $this->handler->handleBatch($this->buffer); - $this->buffer = []; - } - } + $this->flushBuffer(); + + $this->handler->close(); } - /** - * Resets the state of the handler. Stops forwarding records to the wrapped handler. - */ public function reset() { - $this->buffer = array(); - $this->buffering = true; + $this->flushBuffer(); + + $this->resetProcessors(); if ($this->handler instanceof ResettableInterface) { $this->handler->reset(); @@ -166,4 +157,23 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa $this->buffer = []; $this->reset(); } + + /** + * Resets the state of the handler. Stops forwarding records to the wrapped handler. + */ + private function flushBuffer() + { + if (null !== $this->passthruLevel) { + $level = $this->passthruLevel; + $this->buffer = array_filter($this->buffer, function ($record) use ($level) { + return $record['level'] >= $level; + }); + if (count($this->buffer) > 0) { + $this->handler->handleBatch($this->buffer); + } + } + + $this->buffer = []; + $this->buffering = true; + } } diff --git a/src/Monolog/Handler/GroupHandler.php b/src/Monolog/Handler/GroupHandler.php index 3c400631..28b9f162 100644 --- a/src/Monolog/Handler/GroupHandler.php +++ b/src/Monolog/Handler/GroupHandler.php @@ -93,6 +93,8 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface, Reset public function reset() { + $this->resetProcessors(); + foreach ($this->handlers as $handler) { if ($handler instanceof ResettableInterface) { $handler->reset(); diff --git a/src/Monolog/Handler/HandlerInterface.php b/src/Monolog/Handler/HandlerInterface.php index d35161b5..68aed186 100644 --- a/src/Monolog/Handler/HandlerInterface.php +++ b/src/Monolog/Handler/HandlerInterface.php @@ -59,10 +59,18 @@ interface HandlerInterface /** * Closes the handler. * - * This will be called automatically when the object is destroyed if you extend Monolog\Handler\Handler + * Ends a log cycle and frees all resources used by the handler. + * + * Closing a Handler means flushing all buffers and freeing any open resources/handles. * * Implementations have to be idempotent (i.e. it should be possible to call close several times without breakage) * and ideally handlers should be able to reopen themselves on handle() after they have been closed. + * + * This is useful at the end of a request and will be called automatically when the object + * is destroyed if you extend Monolog\Handler\Handler. + * + * If you are thinking of calling this method yourself, most likely you should be + * calling ResettableInterface::reset instead. Have a look. */ public function close(): void; } diff --git a/src/Monolog/Handler/ProcessableHandlerTrait.php b/src/Monolog/Handler/ProcessableHandlerTrait.php index 58821100..ee5871b3 100644 --- a/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -11,6 +11,8 @@ namespace Monolog\Handler; +use Monolog\ResettableInterface; + /** * Helper trait for implementing ProcessableInterface * @@ -57,4 +59,13 @@ trait ProcessableHandlerTrait return $record; } + + protected function resetProcessors() + { + foreach ($this->processors as $processor) { + if ($processor instanceof ResettableInterface) { + $processor->reset(); + } + } + } } diff --git a/src/Monolog/Handler/RollbarHandler.php b/src/Monolog/Handler/RollbarHandler.php index 4df6f15e..f23ac2ee 100644 --- a/src/Monolog/Handler/RollbarHandler.php +++ b/src/Monolog/Handler/RollbarHandler.php @@ -102,7 +102,7 @@ class RollbarHandler extends AbstractProcessingHandler $this->hasRecords = true; } - public function flush() + public function flush(): void { if ($this->hasRecords) { $this->rollbarLogger->flush(); @@ -117,4 +117,14 @@ class RollbarHandler extends AbstractProcessingHandler { $this->flush(); } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->flush(); + + parent::reset(); + } } diff --git a/src/Monolog/Handler/RotatingFileHandler.php b/src/Monolog/Handler/RotatingFileHandler.php index 32fbb877..58f6ac11 100644 --- a/src/Monolog/Handler/RotatingFileHandler.php +++ b/src/Monolog/Handler/RotatingFileHandler.php @@ -67,6 +67,18 @@ class RotatingFileHandler extends StreamHandler } } + /** + * {@inheritdoc} + */ + public function reset() + { + parent::reset(); + + if (true === $this->mustRotate) { + $this->rotate(); + } + } + public function setFilenameFormat($filenameFormat, $dateFormat) { if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { diff --git a/src/Monolog/Logger.php b/src/Monolog/Logger.php index eb98c08f..1c05293c 100644 --- a/src/Monolog/Logger.php +++ b/src/Monolog/Logger.php @@ -333,6 +333,33 @@ class Logger implements LoggerInterface, ResettableInterface return true; } + /** + * Ends a log cycle and frees all resources used by handlers. + * + * Closing a Handler means flushing all buffers and freeing any open resources/handles. + * Handlers that have been closed should be able to accept log records again and re-open + * themselves on demand, but this may not always be possible depending on implementation. + * + * This is useful at the end of a request and will be called automatically on every handler + * when they get destructed. + */ + public function close() + { + foreach ($this->handlers as $handler) { + $handler->close(); + } + } + + /** + * Ends a log cycle and resets all handlers and processors to their initial state. + * + * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal + * state, and getting it back to a state in which it can receive log records again. + * + * This is useful in case you want to avoid logs leaking between two requests or jobs when you + * have a long running process like a worker or an application server serving multiple requests + * in one process. + */ public function reset() { foreach ($this->handlers as $handler) { diff --git a/src/Monolog/ResettableInterface.php b/src/Monolog/ResettableInterface.php index 375b0544..635bc77d 100644 --- a/src/Monolog/ResettableInterface.php +++ b/src/Monolog/ResettableInterface.php @@ -14,8 +14,14 @@ namespace Monolog; /** * Handler or Processor implementing this interface will be reset when Logger::reset() is called. * - * Resetting an Handler or a Processor usually means cleaning all buffers or - * resetting in its internal state. This should also generally close() the handler. + * Resetting ends a log cycle gets them back to their initial state. + * + * Resetting a Handler or a Processor means flushing/cleaning all buffers, resetting internal + * state, and getting it back to a state in which it can receive log records again. + * + * This is useful in case you want to avoid logs leaking between two requests or jobs when you + * have a long running process like a worker or an application server serving multiple requests + * in one process. * * @author Grégoire Pineau */