Kaynağa Gözat

Merge pull request #1503 from gfaugere/redispubsub

Adding Redis Pub/Sub handler (closes #574)
Jordi Boggiano 5 yıl önce
ebeveyn
işleme
9ab131c225

+ 67 - 0
src/Monolog/Handler/RedisPubSubHandler.php

@@ -0,0 +1,67 @@
+<?php declare(strict_types=1);
+
+/*
+ * 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;
+
+use Monolog\Formatter\LineFormatter;
+use Monolog\Formatter\FormatterInterface;
+use Monolog\Logger;
+
+/**
+ * Sends the message to a Redis Pub/Sub channel using PUBLISH
+ *
+ * usage example:
+ *
+ *   $log = new Logger('application');
+ *   $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Logger::WARNING);
+ *   $log->pushHandler($redis);
+ *
+ * @author Gaëtan Faugère <gaetan@fauge.re>
+ */
+class RedisPubSubHandler extends AbstractProcessingHandler
+{
+    private $redisClient;
+    private $channelKey;
+
+    /**
+     * @param \Predis\Client|\Redis $redis  The redis instance
+     * @param string                $key    The channel key to publish records to
+     * @param string|int            $level  The minimum logging level at which this handler will be triggered
+     * @param bool                  $bubble Whether the messages that are handled can bubble up the stack or not
+     */
+    public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true)
+    {
+        if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) {
+            throw new \InvalidArgumentException('Predis\Client or Redis instance required');
+        }
+
+        $this->redisClient = $redis;
+        $this->channelKey = $key;
+
+        parent::__construct($level, $bubble);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function write(array $record): void
+    {
+        $this->redisClient->publish($this->channelKey, $record["formatted"]);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected function getDefaultFormatter(): FormatterInterface
+    {
+        return new LineFormatter();
+    }
+}

+ 76 - 0
tests/Monolog/Handler/RedisPubSubHandlerTest.php

@@ -0,0 +1,76 @@
+<?php
+
+declare(strict_types=1);
+
+/*
+ * 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;
+
+use Monolog\Test\TestCase;
+use Monolog\Logger;
+use Monolog\Formatter\LineFormatter;
+
+class RedisPubSubHandlerTest extends TestCase
+{
+    public function testConstructorShouldThrowExceptionForInvalidRedis()
+    {
+        $this->expectException(\InvalidArgumentException::class);
+
+        new RedisPubSubHandler(new \stdClass(), 'key');
+    }
+
+    public function testConstructorShouldWorkWithPredis()
+    {
+        $redis = $this->createMock('Predis\Client');
+        $this->assertInstanceof('Monolog\Handler\RedisPubSubHandler', new RedisPubSubHandler($redis, 'key'));
+    }
+
+    public function testConstructorShouldWorkWithRedis()
+    {
+        if (!class_exists('Redis')) {
+            $this->markTestSkipped('The redis ext is required to run this test');
+        }
+
+        $redis = $this->createMock('Redis');
+        $this->assertInstanceof('Monolog\Handler\RedisPubSubHandler', new RedisPubSubHandler($redis, 'key'));
+    }
+
+    public function testPredisHandle()
+    {
+        $redis = $this->prophesize('Predis\Client');
+        $redis->publish('key', 'test')->shouldBeCalled();
+        $redis = $redis->reveal();
+
+        $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass(), 'foo' => 34]);
+
+        $handler = new RedisPubSubHandler($redis, 'key');
+        $handler->setFormatter(new LineFormatter("%message%"));
+        $handler->handle($record);
+    }
+
+    public function testRedisHandle()
+    {
+        if (!class_exists('Redis')) {
+            $this->markTestSkipped('The redis ext is required to run this test');
+        }
+
+        $redis = $this->createPartialMock('Redis', ['publish']);
+
+        $redis->expects($this->once())
+            ->method('publish')
+            ->with('key', 'test');
+
+        $record = $this->getRecord(Logger::WARNING, 'test', ['data' => new \stdClass(), 'foo' => 34]);
+
+        $handler = new RedisPubSubHandler($redis, 'key');
+        $handler->setFormatter(new LineFormatter("%message%"));
+        $handler->handle($record);
+    }
+}