Kaynağa Gözat

Adds ability to cap log size in redis

100% backward compatible, defaults to not capping collection size.

Additional constructor param of $capSize added which will ensure logs
list is treated as a FILO queue

Test coverage on new functionality
Matt Wells 10 yıl önce
ebeveyn
işleme
050694291e

+ 39 - 6
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);
+            });
+        }
     }
 
     /**

+ 57 - 0
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);
+    }
 }