diff --git a/src/Monolog/Handler/RedisHandler.php b/src/Monolog/Handler/RedisHandler.php index ee8c2363..7dcd8485 100644 --- a/src/Monolog/Handler/RedisHandler.php +++ b/src/Monolog/Handler/RedisHandler.php @@ -29,14 +29,16 @@ class RedisHandler extends AbstractProcessingHandler { private $redisClient; private $redisKey; + protected $capSize; /** - * @param \Predis\Client|\Redis $redis The redis instance - * @param string $key The key name to push records to - * @param integer $level The minimum logging level at which this handler will be triggered - * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param \Predis\Client|\Redis $redis The redis instance + * @param string $key The key name to push records to + * @param integer $level The minimum logging level at which this handler will be triggered + * @param boolean $bubble Whether the messages that are handled can bubble up the stack or not + * @param integer $capSize Number of entries to limit list size to */ - public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true) + public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false) { if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { throw new \InvalidArgumentException('Predis\Client or Redis instance required'); @@ -44,13 +46,44 @@ class RedisHandler extends AbstractProcessingHandler $this->redisClient = $redis; $this->redisKey = $key; + $this->capSize = $capSize; parent::__construct($level, $bubble); } + /** + * {@inheritDoc} + */ protected function write(array $record) { - $this->redisClient->rpush($this->redisKey, $record["formatted"]); + if ($this->capSize) + { + $this->writeCapped($record); + } else { + $this->redisClient->rpush($this->redisKey, $record["formatted"]); + } + } + + /** + * Write and cap the collection + * Writes the record to the redis list and caps its + * + * @param array $record associative record array + * @return void + */ + protected function writeCapped(array $record) + { + if($this->redisClient instanceof \Redis) { + $this->redisClient->multi() + ->lpush($this->redisKey, $record["formatted"]) + ->ltrim($this->redisKey, 0, $this->capSize) + ->execute(); + } else { + $this->redisClient->transaction(function($tx) use($record) { + $tx->lpush($this->redisKey, $record["formatted"]); + $tx->ltrim($this->redisKey, 0, $this->capSize); + }); + } } /** diff --git a/tests/Monolog/Handler/RedisHandlerTest.php b/tests/Monolog/Handler/RedisHandlerTest.php index 3629f8a2..5a4591c3 100644 --- a/tests/Monolog/Handler/RedisHandlerTest.php +++ b/tests/Monolog/Handler/RedisHandlerTest.php @@ -68,4 +68,61 @@ class RedisHandlerTest extends TestCase $handler->setFormatter(new LineFormatter("%message%")); $handler->handle($record); } + + public function testRedisHandleCapped() + { + $redis = $this->getMock('Redis', array('multi', 'lpush', 'ltrim', 'execute')); + + // Redis uses multi + $redis->expects($this->once()) + ->method('multi') + ->will($this->returnSelf()); + + $redis->expects($this->once()) + ->method('lpush') + ->will($this->returnSelf()); + + $redis->expects($this->once()) + ->method('ltrim') + ->will($this->returnSelf()); + + $redis->expects($this->once()) + ->method('execute') + ->will($this->returnSelf()); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $handler = new RedisHandler($redis, 'key', Logger::DEBUG, true, 10); + $handler->setFormatter(new LineFormatter("%message%")); + $handler->handle($record); + } + + public function testPredisHandleCapped() + { + $redis = $this->getMock('Predis\Client', array('transaction')); + + // Redis uses multi + $redis->expects($this->once()) + ->method('transaction') + ->will($this->returnCallback(function($cb){ + + $redisTransaction = $this->getMock('Predis\Client', array('lpush', 'ltrim')); + + $redisTransaction->expects($this->once()) + ->method('lpush') + ->will($this->returnSelf()); + + $redisTransaction->expects($this->once()) + ->method('ltrim') + ->will($this->returnSelf()); + + $cb($redisTransaction); + })); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $handler = new RedisHandler($redis, 'key', Logger::DEBUG, true, 10); + $handler->setFormatter(new LineFormatter("%message%")); + $handler->handle($record); + } }