mirror of
https://github.com/Seldaek/monolog.git
synced 2025-08-01 19:00:20 +02:00
Added a new ResettableInterface and implemented it where possible.
When one use Monolog in a long process like an AMQP worker with a `FingersCrossedHandler` or `BufferHandler` there is a drawback: as soon as there is an AMQP message that generate a log >= error (for example), all next AMQP messages will output logs, even if theses messages don't generate log where level >= error. In the same context there is a drawback for processor that add an UUID to the logs. The UUID should change for each AMQP messages. --- This patch address this issue with a new interface: `ResettableInterface` interface. Side note: `reset()`, `flush()`, `clear()`, are already used in Monolog. So basically, one can use the `reset()` on the `Logger` and on some `Handler`s / `Processor`s. It's especially useful for * the `FingersCrossedHandler`: it `close()` the buffer, then it `clear()` the buffer. * the `BufferHandler`: it `flush()` the buffer, then it `clear()` the buffer. * the `UidProcessor`: it renew the `uid`.
This commit is contained in:
@@ -19,6 +19,8 @@
|
|||||||
* Fixed table row styling issues in HtmlFormatter
|
* Fixed table row styling issues in HtmlFormatter
|
||||||
* Fixed RavenHandler dropping the message when logging exception
|
* Fixed RavenHandler dropping the message when logging exception
|
||||||
* Fixed WhatFailureGroupHandler skipping processors when using handleBatch
|
* Fixed WhatFailureGroupHandler skipping processors when using handleBatch
|
||||||
|
* Added a `ResettableInterface` in order to reset/reset/clear/flush handlers and processors
|
||||||
|
and implement it where possible
|
||||||
|
|
||||||
### 1.23.0 (2017-06-19)
|
### 1.23.0 (2017-06-19)
|
||||||
|
|
||||||
|
@@ -11,16 +11,17 @@
|
|||||||
|
|
||||||
namespace Monolog\Handler;
|
namespace Monolog\Handler;
|
||||||
|
|
||||||
use Monolog\Logger;
|
|
||||||
use Monolog\Formatter\FormatterInterface;
|
use Monolog\Formatter\FormatterInterface;
|
||||||
use Monolog\Formatter\LineFormatter;
|
use Monolog\Formatter\LineFormatter;
|
||||||
|
use Monolog\Logger;
|
||||||
|
use Monolog\ResettableInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base Handler class providing the Handler structure
|
* Base Handler class providing the Handler structure
|
||||||
*
|
*
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
*/
|
*/
|
||||||
abstract class AbstractHandler implements HandlerInterface
|
abstract class AbstractHandler implements HandlerInterface, ResettableInterface
|
||||||
{
|
{
|
||||||
protected $level = Logger::DEBUG;
|
protected $level = Logger::DEBUG;
|
||||||
protected $bubble = true;
|
protected $bubble = true;
|
||||||
@@ -174,6 +175,17 @@ abstract class AbstractHandler implements HandlerInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
$this->close();
|
||||||
|
|
||||||
|
foreach ($this->processors as $processor) {
|
||||||
|
if ($processor instanceof ResettableInterface) {
|
||||||
|
$processor->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the default formatter.
|
* Gets the default formatter.
|
||||||
*
|
*
|
||||||
|
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
namespace Monolog\Handler;
|
namespace Monolog\Handler;
|
||||||
|
|
||||||
|
use Monolog\ResettableInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base Handler class providing the Handler structure
|
* Base Handler class providing the Handler structure
|
||||||
*
|
*
|
||||||
|
@@ -69,14 +69,19 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
|||||||
} elseif ($format === 'js') {
|
} elseif ($format === 'js') {
|
||||||
static::writeOutput(static::generateScript());
|
static::writeOutput(static::generateScript());
|
||||||
}
|
}
|
||||||
static::reset();
|
static::resetStatic();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
self::resetStatic();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forget all logged records
|
* Forget all logged records
|
||||||
*/
|
*/
|
||||||
public static function reset()
|
public static function resetStatic()
|
||||||
{
|
{
|
||||||
static::$records = array();
|
static::$records = array();
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
namespace Monolog\Handler;
|
namespace Monolog\Handler;
|
||||||
|
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
use Monolog\ResettableInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffers all records until closing the handler and then pass them as batch.
|
* Buffers all records until closing the handler and then pass them as batch.
|
||||||
@@ -114,4 +115,13 @@ class BufferHandler extends AbstractHandler
|
|||||||
$this->bufferSize = 0;
|
$this->bufferSize = 0;
|
||||||
$this->buffer = array();
|
$this->buffer = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
parent::reset();
|
||||||
|
|
||||||
|
if ($this->handler instanceof ResettableInterface) {
|
||||||
|
$this->handler->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ namespace Monolog\Handler;
|
|||||||
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
|
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
|
||||||
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
|
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
|
||||||
use Monolog\Logger;
|
use Monolog\Logger;
|
||||||
|
use Monolog\ResettableInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Buffers all records until a certain level is reached
|
* Buffers all records until a certain level is reached
|
||||||
@@ -147,7 +148,14 @@ class FingersCrossedHandler extends AbstractHandler
|
|||||||
*/
|
*/
|
||||||
public function reset()
|
public function reset()
|
||||||
{
|
{
|
||||||
|
parent::reset();
|
||||||
|
|
||||||
|
$this->buffer = array();
|
||||||
$this->buffering = true;
|
$this->buffering = true;
|
||||||
|
|
||||||
|
if ($this->handler instanceof ResettableInterface) {
|
||||||
|
$this->handler->reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
namespace Monolog\Handler;
|
namespace Monolog\Handler;
|
||||||
|
|
||||||
use Monolog\Formatter\FormatterInterface;
|
use Monolog\Formatter\FormatterInterface;
|
||||||
|
use Monolog\ResettableInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forwards records to multiple handlers
|
* Forwards records to multiple handlers
|
||||||
@@ -90,6 +91,17 @@ class GroupHandler extends AbstractHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
parent::reset();
|
||||||
|
|
||||||
|
foreach ($this->handlers as $handler) {
|
||||||
|
if ($handler instanceof ResettableInterface) {
|
||||||
|
$handler->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Monolog\Handler;
|
namespace Monolog\Handler;
|
||||||
|
|
||||||
|
use Monolog\ResettableInterface;
|
||||||
use Monolog\Formatter\FormatterInterface;
|
use Monolog\Formatter\FormatterInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +31,7 @@ use Monolog\Formatter\FormatterInterface;
|
|||||||
*
|
*
|
||||||
* @author Alexey Karapetov <alexey@karapetov.com>
|
* @author Alexey Karapetov <alexey@karapetov.com>
|
||||||
*/
|
*/
|
||||||
class HandlerWrapper implements HandlerInterface
|
class HandlerWrapper implements HandlerInterface, ResettableInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var HandlerInterface
|
* @var HandlerInterface
|
||||||
@@ -105,4 +106,11 @@ class HandlerWrapper implements HandlerInterface
|
|||||||
{
|
{
|
||||||
return $this->handler->getFormatter();
|
return $this->handler->getFormatter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
if ($this->handler instanceof ResettableInterface) {
|
||||||
|
return $this->handler->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ use Exception;
|
|||||||
*
|
*
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
*/
|
*/
|
||||||
class Logger implements LoggerInterface
|
class Logger implements LoggerInterface, ResettableInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Detailed debug information
|
* Detailed debug information
|
||||||
@@ -354,6 +354,21 @@ class Logger implements LoggerInterface
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
foreach ($this->handlers as $handler) {
|
||||||
|
if ($handler instanceof ResettableInterface) {
|
||||||
|
$handler->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->processors as $processor) {
|
||||||
|
if ($processor instanceof ResettableInterface) {
|
||||||
|
$processor->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a log record at the DEBUG level.
|
* Adds a log record at the DEBUG level.
|
||||||
*
|
*
|
||||||
|
@@ -11,12 +11,14 @@
|
|||||||
|
|
||||||
namespace Monolog\Processor;
|
namespace Monolog\Processor;
|
||||||
|
|
||||||
|
use Monolog\ResettableInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a unique identifier into records
|
* Adds a unique identifier into records
|
||||||
*
|
*
|
||||||
* @author Simon Mönch <sm@webfactory.de>
|
* @author Simon Mönch <sm@webfactory.de>
|
||||||
*/
|
*/
|
||||||
class UidProcessor
|
class UidProcessor implements ResettableInterface
|
||||||
{
|
{
|
||||||
private $uid;
|
private $uid;
|
||||||
|
|
||||||
@@ -26,7 +28,8 @@ class UidProcessor
|
|||||||
throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32');
|
throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->uid = substr(hash('md5', uniqid('', true)), 0, $length);
|
|
||||||
|
$this->uid = $this->generateUid($length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(array $record)
|
public function __invoke(array $record)
|
||||||
@@ -43,4 +46,14 @@ class UidProcessor
|
|||||||
{
|
{
|
||||||
return $this->uid;
|
return $this->uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset()
|
||||||
|
{
|
||||||
|
$this->uid = $this->generateUid(strlen($this->uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function generateUid($length)
|
||||||
|
{
|
||||||
|
return substr(hash('md5', uniqid('', true)), 0, $length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
25
src/Monolog/ResettableInterface.php
Normal file
25
src/Monolog/ResettableInterface.php
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Monolog package.
|
||||||
|
*
|
||||||
|
* (c) Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||||
|
*/
|
||||||
|
interface ResettableInterface
|
||||||
|
{
|
||||||
|
public function reset();
|
||||||
|
}
|
@@ -21,7 +21,7 @@ class BrowserConsoleHandlerTest extends TestCase
|
|||||||
{
|
{
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
BrowserConsoleHandler::reset();
|
BrowserConsoleHandler::resetStatic();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function generateScript()
|
protected function generateScript()
|
||||||
|
@@ -21,7 +21,7 @@ class ChromePHPHandlerTest extends TestCase
|
|||||||
{
|
{
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
TestChromePHPHandler::reset();
|
TestChromePHPHandler::resetStatic();
|
||||||
$_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0';
|
$_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; Chrome/1.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ class TestChromePHPHandler extends ChromePHPHandler
|
|||||||
{
|
{
|
||||||
protected $headers = array();
|
protected $headers = array();
|
||||||
|
|
||||||
public static function reset()
|
public static function resetStatic()
|
||||||
{
|
{
|
||||||
self::$initialized = false;
|
self::$initialized = false;
|
||||||
self::$overflowed = false;
|
self::$overflowed = false;
|
||||||
|
@@ -58,7 +58,7 @@ class FingersCrossedHandlerTest extends TestCase
|
|||||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||||
* @covers Monolog\Handler\FingersCrossedHandler::reset
|
* @covers Monolog\Handler\FingersCrossedHandler::reset
|
||||||
*/
|
*/
|
||||||
public function testHandleRestartBufferingAfterReset()
|
public function testHandleResetBufferingAfterReset()
|
||||||
{
|
{
|
||||||
$test = new TestHandler();
|
$test = new TestHandler();
|
||||||
$handler = new FingersCrossedHandler($test);
|
$handler = new FingersCrossedHandler($test);
|
||||||
@@ -76,7 +76,7 @@ class FingersCrossedHandlerTest extends TestCase
|
|||||||
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
* @covers Monolog\Handler\FingersCrossedHandler::handle
|
||||||
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
* @covers Monolog\Handler\FingersCrossedHandler::activate
|
||||||
*/
|
*/
|
||||||
public function testHandleRestartBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled()
|
public function testHandleResetBufferingAfterBeingTriggeredWhenStopBufferingIsDisabled()
|
||||||
{
|
{
|
||||||
$test = new TestHandler();
|
$test = new TestHandler();
|
||||||
$handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false);
|
$handler = new FingersCrossedHandler($test, Logger::WARNING, 0, false, false);
|
||||||
|
@@ -21,7 +21,7 @@ class FirePHPHandlerTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
TestFirePHPHandler::reset();
|
TestFirePHPHandler::resetStatic();
|
||||||
$_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0';
|
$_SERVER['HTTP_USER_AGENT'] = 'Monolog Test; FirePHP/1.0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ class TestFirePHPHandler extends FirePHPHandler
|
|||||||
{
|
{
|
||||||
protected $headers = array();
|
protected $headers = array();
|
||||||
|
|
||||||
public static function reset()
|
public static function resetStatic()
|
||||||
{
|
{
|
||||||
self::$initialized = false;
|
self::$initialized = false;
|
||||||
self::$sendHeaders = true;
|
self::$sendHeaders = true;
|
||||||
|
@@ -614,4 +614,77 @@ class LoggerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$logger->pushHandler($handler);
|
$logger->pushHandler($handler);
|
||||||
$logger->info('test');
|
$logger->info('test');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testReset()
|
||||||
|
{
|
||||||
|
$logger = new Logger('app');
|
||||||
|
|
||||||
|
$testHandler = new Handler\TestHandler();
|
||||||
|
$bufferHandler = new Handler\BufferHandler($testHandler);
|
||||||
|
$groupHandler = new Handler\GroupHandler(array($bufferHandler));
|
||||||
|
$fingersCrossedHandler = new Handler\FingersCrossedHandler($groupHandler);
|
||||||
|
|
||||||
|
$logger->pushHandler($fingersCrossedHandler);
|
||||||
|
|
||||||
|
$processorUid1 = new Processor\UidProcessor(10);
|
||||||
|
$uid1 = $processorUid1->getUid();
|
||||||
|
$groupHandler->pushProcessor($processorUid1);
|
||||||
|
|
||||||
|
$processorUid2 = new Processor\UidProcessor(5);
|
||||||
|
$uid2 = $processorUid2->getUid();
|
||||||
|
$logger->pushProcessor($processorUid2);
|
||||||
|
|
||||||
|
$getProperty = function ($object, $property) {
|
||||||
|
$reflectionProperty = new \ReflectionProperty(get_class($object), $property);
|
||||||
|
$reflectionProperty->setAccessible(true);
|
||||||
|
|
||||||
|
return $reflectionProperty->getValue($object);
|
||||||
|
};
|
||||||
|
$that = $this;
|
||||||
|
$assertBufferOfBufferHandlerEmpty = function () use ($getProperty, $bufferHandler, $that) {
|
||||||
|
$that->assertEmpty($getProperty($bufferHandler, 'buffer'));
|
||||||
|
};
|
||||||
|
$assertBuffersEmpty = function() use ($assertBufferOfBufferHandlerEmpty, $getProperty, $fingersCrossedHandler, $that) {
|
||||||
|
$assertBufferOfBufferHandlerEmpty();
|
||||||
|
$that->assertEmpty($getProperty($fingersCrossedHandler, 'buffer'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$logger->debug('debug');
|
||||||
|
$logger->reset();
|
||||||
|
$assertBuffersEmpty();
|
||||||
|
$this->assertFalse($testHandler->hasDebugRecords());
|
||||||
|
$this->assertFalse($testHandler->hasErrorRecords());
|
||||||
|
$this->assertNotSame($uid1, $uid1 = $processorUid1->getUid());
|
||||||
|
$this->assertNotSame($uid2, $uid2 = $processorUid2->getUid());
|
||||||
|
|
||||||
|
$logger->debug('debug');
|
||||||
|
$logger->error('error');
|
||||||
|
$logger->reset();
|
||||||
|
$assertBuffersEmpty();
|
||||||
|
$this->assertTrue($testHandler->hasDebugRecords());
|
||||||
|
$this->assertTrue($testHandler->hasErrorRecords());
|
||||||
|
$this->assertNotSame($uid1, $uid1 = $processorUid1->getUid());
|
||||||
|
$this->assertNotSame($uid2, $uid2 = $processorUid2->getUid());
|
||||||
|
|
||||||
|
$logger->info('info');
|
||||||
|
$this->assertNotEmpty($getProperty($fingersCrossedHandler, 'buffer'));
|
||||||
|
$assertBufferOfBufferHandlerEmpty();
|
||||||
|
$this->assertFalse($testHandler->hasInfoRecords());
|
||||||
|
|
||||||
|
$logger->reset();
|
||||||
|
$assertBuffersEmpty();
|
||||||
|
$this->assertFalse($testHandler->hasInfoRecords());
|
||||||
|
$this->assertNotSame($uid1, $uid1 = $processorUid1->getUid());
|
||||||
|
$this->assertNotSame($uid2, $uid2 = $processorUid2->getUid());
|
||||||
|
|
||||||
|
$logger->notice('notice');
|
||||||
|
$logger->emergency('emergency');
|
||||||
|
$logger->reset();
|
||||||
|
$assertBuffersEmpty();
|
||||||
|
$this->assertFalse($testHandler->hasInfoRecords());
|
||||||
|
$this->assertTrue($testHandler->hasNoticeRecords());
|
||||||
|
$this->assertTrue($testHandler->hasEmergencyRecords());
|
||||||
|
$this->assertNotSame($uid1, $processorUid1->getUid());
|
||||||
|
$this->assertNotSame($uid2, $processorUid2->getUid());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user