diff --git a/src/Monolog/Handler/FingersCrossedHandler.php b/src/Monolog/Handler/FingersCrossedHandler.php index 126f5178..de6398e4 100644 --- a/src/Monolog/Handler/FingersCrossedHandler.php +++ b/src/Monolog/Handler/FingersCrossedHandler.php @@ -11,18 +11,29 @@ namespace Monolog\Handler; +use Monolog\Logger; + +/** + * FingersCrossedHandler buffers all messages until a certain level is reached + * + * The advantage of this approach is that you don't get any clutter in your log files. + * Only requests which actually trigger an error (or whatever your actionLevel is) will be + * in the logs, but they will contain all messages, not only those above the level threshold. + * + * @author Jordi Boggiano + */ class FingersCrossedHandler extends AbstractHandler { protected $handler; protected $actionLevel; + protected $buffering = true; protected $bufferSize; - protected $enabled = false; protected $buffer = array(); /** * @param callback|HandlerInterface $handler Handler or factory callback($message, $fingersCrossedHandler). - * @param int $actionLevel the level at which this handler is triggered. - * @param int $bufferSize how many entries should be buffered at most, beyond that the oldest items are removed from the buffer. + * @param int $actionLevel The level at which this handler is triggered. + * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. * @param Boolean $bubble */ public function __construct($handler, $actionLevel = Logger::WARNING, $bufferSize = 0, $bubble = false) @@ -33,15 +44,24 @@ class FingersCrossedHandler extends AbstractHandler $this->bubble = $bubble; } + /** + * Handles a message + * + * Messages are buffered until one of them matches the actionLevel. From then + * on, unless reset() is called, all messages are passed to the wrapped handler. + * + * @param array $message Message + * @return Boolean Whether the next handler in the stack should be called. + */ public function handle($message) { - if (!$this->enabled) { + if ($this->buffering) { $this->buffer[] = $message; if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) { array_shift($this->buffer); } if ($message['level'] >= $this->actionLevel) { - $this->enabled = true; + $this->buffering = false; if (!$this->handler instanceof AbstractHandler) { $this->handler = $this->handler($message, $this); } @@ -56,11 +76,17 @@ class FingersCrossedHandler extends AbstractHandler return false === $this->bubble; } + /** + * Resets the state of the handler. Stops forwarding messages to the wrapped handler. + */ public function reset() { - $this->enabled = false; + $this->buffering = true; } + /** + * Implemented to comply with the AbstractHandler rqeuirements. Can not be called. + */ public function write($message) { throw new \LogicException('This method should not be called directly on the FingersCrossedHandler.'); diff --git a/tests/Monolog/Handler/FingersCrossedHandlerTest.php b/tests/Monolog/Handler/FingersCrossedHandlerTest.php new file mode 100644 index 00000000..3cb6932f --- /dev/null +++ b/tests/Monolog/Handler/FingersCrossedHandlerTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +class FingersCrossedHandlerTest extends \PHPUnit_Framework_TestCase +{ + public function testHandleBuffers() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test); + $handler->handle($this->getMessage(Logger::DEBUG)); + $handler->handle($this->getMessage(Logger::INFO)); + $this->assertFalse($test->hasDebugMessages()); + $this->assertFalse($test->hasInfoMessages()); + $handler->handle($this->getMessage(Logger::WARNING)); + $this->assertTrue($test->hasInfoMessages()); + $this->assertTrue(count($test->getMessages()) === 3); + } + + public function testHandleStopsBufferingAfterTrigger() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test); + $handler->handle($this->getMessage(Logger::WARNING)); + $handler->handle($this->getMessage(Logger::DEBUG)); + $this->assertTrue($test->hasWarningMessages()); + $this->assertTrue($test->hasDebugMessages()); + } + + public function testHandleBufferLimit() + { + $test = new TestHandler(); + $handler = new FingersCrossedHandler($test, Logger::WARNING, 2); + $handler->handle($this->getMessage(Logger::DEBUG)); + $handler->handle($this->getMessage(Logger::DEBUG)); + $handler->handle($this->getMessage(Logger::INFO)); + $handler->handle($this->getMessage(Logger::WARNING)); + $this->assertTrue($test->hasWarningMessages()); + $this->assertTrue($test->hasInfoMessages()); + $this->assertFalse($test->hasDebugMessages()); + } + + protected function getMessage($level = Logger::WARNING) + { + return array( + 'level' => $level, + 'level_name' => 'WARNING', + 'channel' => 'log', + 'message' => 'foo', + 'datetime' => new \DateTime, + 'extra' => array(), + ); + } +}