Преглед изворни кода

Merge pull request #602 from ninjapenguin/add-redis-apped-collection

Adds ability to cap log size in redis
Jordi Boggiano пре 10 година
родитељ
комит
cf6fa57dd4
2 измењених фајлова са 97 додато и 6 уклоњено
  1. 41 6
      src/Monolog/Handler/RedisHandler.php
  2. 56 0
      tests/Monolog/Handler/RedisHandlerTest.php

+ 41 - 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,46 @@ 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()
+                ->rpush($this->redisKey, $record["formatted"])
+                ->ltrim($this->redisKey, -$this->capSize, -1)
+                ->execute();
+        } else {
+            $redisKey = $this->redisKey;
+            $capSize = $this->capSize;
+            $this->redisClient->transaction(function($tx) use($record, $redisKey, $capSize) {
+                $tx->rpush($redisKey, $record["formatted"]);
+                $tx->ltrim($redisKey, -$capSize, -1);
+            });
+        }
     }
 
     /**

+ 56 - 0
tests/Monolog/Handler/RedisHandlerTest.php

@@ -68,4 +68,60 @@ class RedisHandlerTest extends TestCase
         $handler->setFormatter(new LineFormatter("%message%"));
         $handler->handle($record);
     }
+
+    public function testRedisHandleCapped()
+    {
+        $redis = $this->getMock('Redis', array('multi', 'rpush', 'ltrim', 'execute'));
+
+        // Redis uses multi
+        $redis->expects($this->once())
+            ->method('multi')
+            ->will($this->returnSelf());
+
+        $redis->expects($this->once())
+            ->method('rpush')
+            ->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'));
+
+        $redisTransaction = $this->getMock('Predis\Client', array('rpush', 'ltrim'));
+
+        $redisTransaction->expects($this->once())
+            ->method('rpush')
+            ->will($this->returnSelf());
+
+        $redisTransaction->expects($this->once())
+            ->method('ltrim')
+            ->will($this->returnSelf());
+
+        // Redis uses multi
+        $redis->expects($this->once())
+            ->method('transaction')
+            ->will($this->returnCallback(function($cb) use ($redisTransaction){
+                $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);
+    }
 }