From e28239473624c6a4419eb6da34d3f26c4297c778 Mon Sep 17 00:00:00 2001 From: Markus Bachmann Date: Thu, 23 Aug 2012 19:54:04 +0200 Subject: [PATCH] Add couchdb handler --- README.mdown | 2 + composer.json | 4 +- src/Monolog/Handler/CouchDBHandler.php | 72 +++++++++++++++++++ .../Handler/DoctrineCouchDBHandler.php | 45 ++++++++++++ tests/Monolog/Handler/CouchDBHandlerTest.php | 41 +++++++++++ .../Handler/DoctrineCouchDBHandlerTest.php | 52 ++++++++++++++ 6 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 src/Monolog/Handler/CouchDBHandler.php create mode 100644 src/Monolog/Handler/DoctrineCouchDBHandler.php create mode 100644 tests/Monolog/Handler/CouchDBHandlerTest.php create mode 100644 tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php diff --git a/README.mdown b/README.mdown index c051eb19..0174614f 100644 --- a/README.mdown +++ b/README.mdown @@ -114,6 +114,8 @@ Handlers - _AmqpHandler_: Logs records to an [amqp](http://www.amqp.org/) compatible server. Requires the [php-amqp](http://pecl.php.net/package/amqp) extension (1.0+). - _CubeHandler_: Logs records to a [Cube](http://square.github.com/cube/) server. +- _CouchDBHandler: Logs records to the CouchDB server +- _DoctrineCouchDBHandler: Logs records to the CouchDB server. You should use this handler, if you already use the doctrine/couchdb-odm Wrappers / Special Handlers --------------------------- diff --git a/composer.json b/composer.json index 03829a81..7d8964c6 100644 --- a/composer.json +++ b/composer.json @@ -16,10 +16,12 @@ "php": ">=5.3.0" }, "require-dev": { - "mlehner/gelf-php": "1.0.*" + "mlehner/gelf-php": "1.0.*", + "doctrine/couchdb": "dev-master" }, "suggest": { "mlehner/gelf-php": "Allow sending log messages to a GrayLog2 server", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", "ext-mongo": "Allow sending log messages to a MongoDB server" }, diff --git a/src/Monolog/Handler/CouchDBHandler.php b/src/Monolog/Handler/CouchDBHandler.php new file mode 100644 index 00000000..4877b345 --- /dev/null +++ b/src/Monolog/Handler/CouchDBHandler.php @@ -0,0 +1,72 @@ + + * + * 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\JsonFormatter; +use Monolog\Logger; + +/** + * CouchDB handler + * + * @author Markus Bachmann + */ +class CouchDBHandler extends AbstractProcessingHandler +{ + private $options; + + public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true) + { + $this->options = array_merge(array( + 'host' => 'localhost', + 'port' => 5984, + 'dbname' => 'logger', + 'username' => null, + 'password' => null, + ), $options); + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $basicAuth = null; + if ($this->options['username']) { + $basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']); + } + + $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname']; + $context = stream_context_create(array( + 'http' => array( + 'method' => 'POST', + 'content' => $record['formatted'], + 'ignore_errors' => true, + 'max_redirects' => 0, + 'header' => 'Content-type: application/json', + ) + )); + + if (false === @file_get_contents($url, null, $context)) { + throw new \RuntimeException(sprintf('Could not connect to %s', $url)); + } + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new JsonFormatter(); + } +} diff --git a/src/Monolog/Handler/DoctrineCouchDBHandler.php b/src/Monolog/Handler/DoctrineCouchDBHandler.php new file mode 100644 index 00000000..c3bb3c97 --- /dev/null +++ b/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -0,0 +1,45 @@ + + * + * 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; +use Monolog\Formatter\NormalizerFormatter; +use Doctrine\CouchDB\CouchDBClient; + +/** + * CouchDB handler + * + * @author Markus Bachmann + */ +class DoctrineCouchDBHandler extends AbstractProcessingHandler +{ + private $client; + + public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true) + { + $this->client = $client; + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $this->client->postDocument($record['formatted']); + } + + protected function getDefaultFormatter() + { + return new NormalizerFormatter; + } +} \ No newline at end of file diff --git a/tests/Monolog/Handler/CouchDBHandlerTest.php b/tests/Monolog/Handler/CouchDBHandlerTest.php new file mode 100644 index 00000000..78a1d15c --- /dev/null +++ b/tests/Monolog/Handler/CouchDBHandlerTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class CouchDBHandlerTest extends TestCase +{ + public function testHandle() + { + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $expected = array( + 'message' => 'test', + 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34), + 'level' => Logger::WARNING, + 'level_name' => 'WARNING', + 'channel' => 'test', + 'datetime' => $record['datetime']->format('Y-m-d H:i:s'), + 'extra' => array(), + ); + + $handler = new CouchDBHandler(); + + try { + $handler->handle($record); + } catch (\RuntimeException $e) { + $this->markTestSkipped('Could not connect to couchdb server on http://localhost:5984'); + } + } +} diff --git a/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php new file mode 100644 index 00000000..d67da90a --- /dev/null +++ b/tests/Monolog/Handler/DoctrineCouchDBHandlerTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\TestCase; +use Monolog\Logger; + +class DoctrineCouchDBHandlerTest extends TestCase +{ + protected function setup() + { + if (!class_exists('Doctrine\CouchDB\CouchDBClient')) { + $this->markTestSkipped('The "doctrine/couchdb" package is not installed'); + } + } + + public function testHandle() + { + $client = $this->getMockBuilder('Doctrine\\CouchDB\\CouchDBClient') + ->setMethods(array('postDocument')) + ->disableOriginalConstructor() + ->getMock(); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $expected = array( + 'message' => 'test', + 'context' => array('data' => '[object] (stdClass: {})', 'foo' => 34), + 'level' => Logger::WARNING, + 'level_name' => 'WARNING', + 'channel' => 'test', + 'datetime' => $record['datetime']->format('Y-m-d H:i:s'), + 'extra' => array(), + ); + + $client->expects($this->once()) + ->method('postDocument') + ->with($expected); + + $handler = new DoctrineCouchDBHandler($client); + $handler->handle($record); + } +}