diff --git a/README.mdown b/README.mdown index b9d6933f..1a496fd4 100644 --- a/README.mdown +++ b/README.mdown @@ -111,6 +111,9 @@ Handlers - _GelfHandler_: Logs records to a [Graylog2](http://www.graylog2.org) server. - _SocketHandler_: Logs records to [sockets](http://php.net/fsockopen), use this for UNIX and TCP sockets. See an [example](https://github.com/Seldaek/monolog/blob/master/doc/sockets.md). +- _AmqpHandler_L Logs records using [amqp](php.net/manual/en/book.amqp.php) protocol to the RabbitMQ server. + Note: handler needs an installed amqp version > 1. + For instructions on installation look in (http://lv.php.net/manual/en/amqp.installation.php) Wrappers / Special Handlers --------------------------- @@ -161,6 +164,7 @@ Requirements - Any flavor of PHP 5.3 should do - [optional] PHPUnit 3.5+ to execute the test suite (phpunit --version) +- [optional] installed amqp library to use AmqpHandler. Submitting bugs and feature requests ------------------------------------ diff --git a/src/Monolog/Handler/AmqpHandler.php b/src/Monolog/Handler/AmqpHandler.php new file mode 100644 index 00000000..7c8af90e --- /dev/null +++ b/src/Monolog/Handler/AmqpHandler.php @@ -0,0 +1,67 @@ + + * + * 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\JsonFormatter; + +class AmqpHandler extends AbstractProcessingHandler +{ + /** + * @var \AMQPExchange $exchange + */ + protected $exchange; + + /** + * @param \AMQPExchange $exchange AMQP exchange, ready for use + * @param string $exchangeName + * @param string $issuer isser name + * @param int $level + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + */ + public function __construct(\AMQPExchange $exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true) + { + $this->exchange = $exchange; + $this->exchange->setName($exchangeName); + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record) + { + $data = $record["formatted"]; + + $routingKey = sprintf('%s.%s', + substr($record['level_name'], 0, 4), + $record['channel']); + + //we do not check return value because no handler really does + $this->exchange->publish($data, + strtolower($routingKey), + 0, + array( + 'delivery_mode' => 2, + 'Content-type' => 'application/json' + )); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter() + { + return new JsonFormatter(); + } +} diff --git a/tests/Monolog/Handler/AmqpExchangeMock.php b/tests/Monolog/Handler/AmqpExchangeMock.php new file mode 100644 index 00000000..2ed311ea --- /dev/null +++ b/tests/Monolog/Handler/AmqpExchangeMock.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +class MockAMQPExchange extends \AMQPExchange +{ + public function __construct() + { + } + + public function publish($message, $routing_key, $params = 0, $attributes = array()) + { + return true; + } + + public function setName($name) + { + return true; + } +} \ No newline at end of file diff --git a/tests/Monolog/Handler/AmqpHandlerTest.php b/tests/Monolog/Handler/AmqpHandlerTest.php new file mode 100644 index 00000000..201da5cc --- /dev/null +++ b/tests/Monolog/Handler/AmqpHandlerTest.php @@ -0,0 +1,61 @@ + + * + * 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; +use Monolog\Handler\MockAMQPExchange; + +/** + * @covers Monolog\Handler\RotatingFileHandler + */ +class AmqpHandlerTest extends TestCase +{ + public function setUp() + { + if (!class_exists('AMQPConnection') || !class_exists('AMQPExchange')) { + $this->markTestSkipped("amqp-php not installed"); + } + + if (!class_exists('AMQPChannel')) { + $this->markTestSkipped("Please update AMQP to version >= 1"); + } + } + + public function testHandle() + { + $exchange = $this->getExchange(); + + $handler = new AmqpHandler($exchange, 'log'); + + $record = $this->getRecord(Logger::WARNING, 'test', array('data' => new \stdClass, 'foo' => 34)); + + $handler->handle($record); + } + + protected function getExchange() + { + /* sorry, but PHP bug in zend_object_store_get_object segfaults + php where using mocks on AMQP classes. should be fixed someday, + but now it's time for some shitcode (see below) + $exchange = $this->getMockBuilder('\AMQPExchange') + ->setConstructorArgs(array($this->getMock('\AMQPChannel'))) + ->setMethods(array('setName')) + ->getMock(); + + $exchange->expects($this->any()) + ->method('setName') + ->will($this->returnValue(true)); + */ + return new MockAMQPExchange(); + } +} \ No newline at end of file