Added LoggerAppenderAMQP Signed-off-by: Ivan Habunek <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/logging-log4php/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4php/commit/c2930f29 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4php/tree/c2930f29 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4php/diff/c2930f29 Branch: refs/heads/develop Commit: c2930f2946c981cfd878f02415b0fa53f5a43691 Parents: af810f1 Author: Dmitriy Ulyanov <[email protected]> Authored: Mon Feb 24 01:41:15 2014 +0400 Committer: Ivan Habunek <[email protected]> Committed: Thu May 15 09:28:29 2014 +0200 ---------------------------------------------------------------------- src/examples/php/appender_amqp.php | 22 + src/examples/resources/appender_amqp.xml | 32 ++ src/main/php/LoggerAutoloader.php | 1 + src/main/php/appenders/LoggerAppenderAMQP.php | 576 +++++++++++++++++++ src/site/site.xml | 1 + src/site/xdoc/docs/appenders/amqp.xml | 197 +++++++ .../php/appenders/LoggerAppenderAMQPTest.php | 281 +++++++++ 7 files changed, 1110 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/c2930f29/src/examples/php/appender_amqp.php ---------------------------------------------------------------------- diff --git a/src/examples/php/appender_amqp.php b/src/examples/php/appender_amqp.php new file mode 100644 index 0000000..c59b726 --- /dev/null +++ b/src/examples/php/appender_amqp.php @@ -0,0 +1,22 @@ +<?php +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +require_once dirname(__FILE__).'/../../main/php/Logger.php'; +Logger::configure(dirname(__FILE__).'/../resources/appender_amqp.xml'); + +$logger = Logger::getLogger('main'); +$logger->debug("Hello World!"); http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/c2930f29/src/examples/resources/appender_amqp.xml ---------------------------------------------------------------------- diff --git a/src/examples/resources/appender_amqp.xml b/src/examples/resources/appender_amqp.xml new file mode 100644 index 0000000..39b4216 --- /dev/null +++ b/src/examples/resources/appender_amqp.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<log4php:configuration xmlns:log4php="http://logging.apache.org/log4php/" threshold="all"> + <appender name="default" class="LoggerAppenderAMQP"> + <param name="host" value="localhost" /> + <param name="port" value="5672" /> + <param name="vhost" value="/" /> + <param name="login" value="my_login" /> + <param name="password" value="my_secret_password" /> + <param name="exchangeName" value="my_exchange" /> + <param name="routingKey" value="php_application" /> + </appender> + <root> + <level value="DEBUG" /> + <appender_ref ref="default" /> + </root> +</log4php:configuration> http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/c2930f29/src/main/php/LoggerAutoloader.php ---------------------------------------------------------------------- diff --git a/src/main/php/LoggerAutoloader.php b/src/main/php/LoggerAutoloader.php index a87d04a..d633562 100644 --- a/src/main/php/LoggerAutoloader.php +++ b/src/main/php/LoggerAutoloader.php @@ -54,6 +54,7 @@ class LoggerAutoloader { 'LoggerThrowableInformation' => '/LoggerThrowableInformation.php', // Appenders + 'LoggerAppenderAMQP' => '/appenders/LoggerAppenderAMQP.php', 'LoggerAppenderConsole' => '/appenders/LoggerAppenderConsole.php', 'LoggerAppenderDailyFile' => '/appenders/LoggerAppenderDailyFile.php', 'LoggerAppenderEcho' => '/appenders/LoggerAppenderEcho.php', http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/c2930f29/src/main/php/appenders/LoggerAppenderAMQP.php ---------------------------------------------------------------------- diff --git a/src/main/php/appenders/LoggerAppenderAMQP.php b/src/main/php/appenders/LoggerAppenderAMQP.php new file mode 100644 index 0000000..2cfdb86 --- /dev/null +++ b/src/main/php/appenders/LoggerAppenderAMQP.php @@ -0,0 +1,576 @@ +<?php +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * AMQPAppender appends log events to a AMQP. + * + * This appender uses a layout. + * Compatible with php_amqp versions: 1.0.8 - 1.3.0 + * + * This class was originally contributed by Dmitry Ulyanov. + * + * ## Configurable parameters: ## + * + * - **host** - Server on which AMQP instance is located. + * - **port** - Port on which the instance is bound. + * - **vhost** - The name of the "virtual host". + * - **login** - Login used to connect to the AMQP server. + * - **password** - Password used to connect to the AMQP server. + * - **exchangeName** - Name of AMQP exchange which used to routing logs. + * - **exchangeType** - Type of AMQP exchange (direct | fanout). "direct" type is default. + * - **routingKey** - Routing key which used to routing logs. Set up AMQP server + * to route messages with this key to your queue + * - **contentType** - AMQP message "content-type" header. Example: "application/json", "application/octet-stream". + * Default - "text/plain". + * - **contentEncoding** - AMQP message "content-encoding" header. Default - "UTF-8". + * - **flushOnShutdown** - Stash logs and send on shutdown or send immediately. + * You can show content before start sending logs to AMQP. Disabled by default. + * - **connectionTimeout** - Connection timeout (in seconds). Default is 0.5. + * + * @package log4php + * @subpackage appenders + * @since 3.0 + * @author Dmitry Ulyanov [email protected] + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @link http://logging.apache.org/log4php/docs/appenders/amqp.html Appender documentation + * @link http://github.com/d-ulyanov/log4php-graylog2 Dmitry Ulyanov's original submission + * @link http://www.rabbitmq.com/ RabbitMQ website + */ +class LoggerAppenderAMQP extends LoggerAppender +{ + /** Default value for {@link $host} */ + const DEFAULT_AMQP_HOST = 'localhost'; + + /** Default value for {@link $port} */ + const DEFAULT_AMQP_PORT = 5672; + + /** Default value for {@link $vhost} */ + const DEFAULT_AMQP_VHOST = '/'; + + /** Default value for {@link $login} */ + const DEFAULT_AMQP_LOGIN = 'guest'; + + /** Default value for {@link $password} */ + const DEFAULT_AMQP_PASSWORD = 'guest'; + + + /** + * Server on which AMQP instance is located + * @var string + */ + protected $host = self::DEFAULT_AMQP_HOST; + + /** + * Port on which the instance is bound + * @var int + */ + protected $port = self::DEFAULT_AMQP_PORT; + + /** + * The name of the "virtual host" + * @var string + */ + protected $vhost = self::DEFAULT_AMQP_VHOST; + + /** + * Login used to connect to the AMQP server + * @var string + */ + protected $login = self::DEFAULT_AMQP_LOGIN; + + /** + * Password used to connect to the AMQP server + * @var string + */ + protected $password = self::DEFAULT_AMQP_PASSWORD; + + /** + * Name of AMQP exchange which used to routing logs + * @var string + */ + protected $exchangeName; + + /** + * Type of AMQP exchange + * @var string + */ + protected $exchangeType = 'direct'; + + /** + * Routing key which used to routing logs + * @var string + */ + protected $routingKey; + + /** + * Connection timeout in seconds + * @var float + */ + protected $connectionTimeout = 0.5; + + /** + * Content-type header + * @var string + */ + protected $contentType = 'text/plain'; + + /** + * Content-encoding header + * @var string + */ + protected $contentEncoding = 'UTF-8'; + + /** + * Send logs immediately or stash it and send on shutdown + * @var boolean + */ + protected $flushOnShutdown = false; + + /** + * @var AMQPConnection + */ + protected $AMQPConnection; + + /** + * @var AMQPExchange + */ + protected $AMQPExchange; + + /** + * Stashed logs + * @var array + */ + protected $logsStash = array(); + + /** + * Forwards the logging event to the AMQP. + * @param LoggerLoggingEvent $event + */ + protected function append(LoggerLoggingEvent $event) + { + $this->processLog( + $this->layout->format($event), + $this->getFlushOnShutdown() + ); + } + + /** + * @param string $message + * @param boolean $flushOnShutdown + */ + public function processLog($message, $flushOnShutdown) + { + if ($flushOnShutdown) { + $this->stashLog($message); + } else { + $this->sendLogToAMQP($message); + } + } + + /** + * Setup AMQP connection. + * Based on defined options, this method connects to the AMQP + * and creates a {@link $AMQPConnection} and {@link $AMQPExchange}. + */ + public function activateOptions() { + try { + $connection = $this->createAMQPConnection( + $this->getHost(), + $this->getPort(), + $this->getVhost(), + $this->getLogin(), + $this->getPassword(), + $this->getConnectionTimeout() + ); + + $this->setAMQPConnection($connection); + + $exchange = $this->createAMQPExchange( + $connection, + $this->getExchangeName(), + $this->getExchangeType() + ); + + $this->setAMQPExchange($exchange); + } catch (AMQPConnectionException $e) { + $this->closed = true; + $this->warn(sprintf('Failed to connect to amqp server: %s', $e->getMessage())); + } catch (AMQPChannelException $e) { + $this->closed = true; + $this->warn(sprintf('Failed to open amqp channel: %s', $e->getMessage())); + } catch (AMQPExchangeException $e) { + $this->closed = true; + $this->warn(sprintf('Failed to declare amqp exchange: %s', $e->getMessage())); + } catch (Exception $e) { + $this->closed = true; + $this->warn(sprintf('Amqp connection exception: %s', $e->getMessage())); + } + } + + /** + * @param string $host + * @param int $port + * @param string $vhost + * @param string $login + * @param string $password + * @param float $connectionTimeout + * @return AMQPConnection + * @throws AMQPConnectionException + * @throws Exception + */ + protected function createAMQPConnection($host, $port, $vhost, $login, $password, $connectionTimeout) + { + $connection = new AMQPConnection(); + $connection->setHost($host); + $connection->setPort($port); + $connection->setVhost($vhost); + $connection->setLogin($login); + $connection->setPassword($password); + $connection->setReadTimeout($connectionTimeout); + + if (!$connection->connect()) { + throw new Exception('Cannot connect to the broker'); + } + + return $connection; + } + + /** + * @param AMQPConnection $AMQPConnection + * @param $exchangeName + * @param $exchangeType + * @return AMQPExchange + * @throws AMQPConnectionException + * @throws AMQPExchangeException + * @throws Exception + */ + protected function createAMQPExchange($AMQPConnection, $exchangeName, $exchangeType) + { + $channel = new AMQPChannel($AMQPConnection); + $exchange = new AMQPExchange($channel); + $exchange->setName($exchangeName); + $exchange->setType($exchangeType); + $exchange->setFlags(AMQP_DURABLE); + + // Since php_amqp 1.2.0: deprecate AMQPExchange::declare() in favor of AMQPExchange::declareExchange() + $declareMethodName = method_exists($exchange, 'declareExchange') ? 'declareExchange' : 'declare'; + + if (!$exchange->$declareMethodName()) { + throw new Exception('Cannot declare exchange'); + } + + return $exchange; + } + + /** + * @param AMQPConnection $AMQPConnection + */ + protected function setAMQPConnection($AMQPConnection) + { + $this->AMQPConnection = $AMQPConnection; + } + + /** + * @return AMQPConnection + */ + public function getAMQPConnection() + { + return $this->AMQPConnection; + } + + /** + * @param AMQPExchange $AMQPExchange + */ + protected function setAMQPExchange($AMQPExchange) + { + $this->AMQPExchange = $AMQPExchange; + } + + /** + * @return AMQPExchange + */ + public function getAMQPExchange() + { + return $this->AMQPExchange; + } + + /** + * @param string $AMQPRoutingKey + */ + public function setRoutingKey($AMQPRoutingKey) + { + $this->setString('routingKey', $AMQPRoutingKey); + } + + /** + * @return string + */ + public function getRoutingKey() + { + return $this->routingKey; + } + + /** + * @param string $host + */ + public function setHost($host) + { + $this->setString('host', $host); + } + + /** + * @return string + */ + public function getHost() + { + return $this->host; + } + + /** + * @param string $login + */ + public function setLogin($login) + { + $this->setString('login', $login); + } + + /** + * @return string + */ + public function getLogin() + { + return $this->login; + } + + /** + * @param string $password + */ + public function setPassword($password) + { + $this->setString('password', $password); + } + + /** + * @return string + */ + public function getPassword() + { + return $this->password; + } + + /** + * @param int $port + */ + public function setPort($port) + { + $this->setPositiveInteger('port', $port); + } + + /** + * @return int + */ + public function getPort() + { + return $this->port; + } + + /** + * @param string $vhost + */ + public function setVhost($vhost) + { + $this->setString('vhost', $vhost); + } + + /** + * @return string + */ + public function getVhost() + { + return $this->vhost; + } + + /** + * @param string $exchange + */ + public function setExchangeName($exchange) + { + $this->setString('exchangeName', $exchange); + } + + /** + * @return string + */ + public function getExchangeName() + { + return $this->exchangeName; + } + + /** + * @param string $exchangeType + */ + public function setExchangeType($exchangeType) + { + $this->setString('exchangeType', $exchangeType); + } + + /** + * @return string + */ + public function getExchangeType() + { + return $this->exchangeType; + } + + /** + * @param string $contentEncoding + */ + public function setContentEncoding($contentEncoding) + { + $this->setString('contentEncoding', $contentEncoding); + } + + /** + * @return string + */ + public function getContentEncoding() + { + return $this->contentEncoding; + } + + /** + * @param string $contentType + */ + public function setContentType($contentType) + { + $this->setString('contentType', $contentType); + } + + /** + * @return string + */ + public function getContentType() + { + return $this->contentType; + } + + /** + * @param float $connectionTimeout + */ + public function setConnectionTimeout($connectionTimeout) + { + if (is_numeric($connectionTimeout) && $connectionTimeout > 0) { + $this->connectionTimeout = floatval($connectionTimeout); + } else { + $this->warn("Invalid value given for 'connectionTimeout' property: [$connectionTimeout]. Expected a positive float. Property not changed."); + } + } + + /** + * @return float + */ + public function getConnectionTimeout() + { + return $this->connectionTimeout; + } + + /** + * @param boolean $flushOnShutdown + */ + public function setFlushOnShutdown($flushOnShutdown) + { + $this->setBoolean('flushOnShutdown', $flushOnShutdown); + } + + /** + * @return boolean + */ + public function getFlushOnShutdown() + { + return $this->flushOnShutdown; + } + + /** + * @param array $logs Array of strings + */ + public function sendLogsArrayToAMQP($logs) + { + foreach ($logs as $log) { + if ($this->closed) { + break; + } + + $this->sendLogToAMQP($log); + } + } + + /** + * @param string $log + */ + public function sendLogToAMQP($log) + { + try { + $this->getAMQPExchange()->publish( + $log, + $this->getRoutingKey(), + AMQP_NOPARAM, + array( + 'content_type' => $this->getContentType(), + 'content_encoding' => $this->getContentEncoding() + ) + ); + } catch (AMQPConnectionException $e) { + $this->closed = true; + $this->warn(sprintf('Connection to the broker was lost: %s', $e->getMessage())); + } catch (AMQPChannelException $e) { + $this->closed = true; + $this->warn(sprintf('Channel is not open: %s', $e->getMessage())); + } catch (AMQPExchangeException $e) { + $this->closed = true; + $this->warn(sprintf('Failed to publish message: %s', $e->getMessage())); + } catch (Exception $e) { + $this->warn(sprintf('Failed to publish message, unknown exception: %s', $e->getMessage())); + } + } + + /** + * @param string $log + */ + public function stashLog($log) + { + $this->logsStash[] = $log; + } + + public function cleanStashedLogs() + { + $this->logsStash = array(); + } + + public function close() + { + if ($this->getFlushOnShutdown()) { + $this->sendLogsArrayToAMQP($this->logsStash); + $this->cleanStashedLogs(); + } + + $this->setAMQPExchange(null); + $this->setAMQPConnection(null); + + parent::close(); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/c2930f29/src/site/site.xml ---------------------------------------------------------------------- diff --git a/src/site/site.xml b/src/site/site.xml index cd829ba..9eb665b 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -44,6 +44,7 @@ <item name="Configuration" href="/docs/configuration.html" /> <item name="Loggers" href="/docs/loggers.html" /> <item name="Appenders" href="/docs/appenders.html" collapse="true"> + <item name="LoggerAppenderAMQP" href="/docs/appenders/amqp.html" /> <item name="LoggerAppenderConsole" href="/docs/appenders/console.html" /> <item name="LoggerAppenderDailyFile" href="/docs/appenders/daily-file.html" /> <item name="LoggerAppenderEcho" href="/docs/appenders/echo.html" /> http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/c2930f29/src/site/xdoc/docs/appenders/amqp.xml ---------------------------------------------------------------------- diff --git a/src/site/xdoc/docs/appenders/amqp.xml b/src/site/xdoc/docs/appenders/amqp.xml new file mode 100644 index 0000000..31478d7 --- /dev/null +++ b/src/site/xdoc/docs/appenders/amqp.xml @@ -0,0 +1,197 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd"> + + <properties> + <title>LoggerAppenderAMQP</title> + </properties> + + <body> + <section name="LoggerAppenderAMQP"> + + <p><code>LoggerAppenderAMQP</code> appends log events to a AMQP instance.</p> + + <p>The Advanced Message Queuing Protocol (AMQP) is an open standard application layer protocol + for message-oriented middleware. The defining features of AMQP are message orientation, + queuing, routing (including point-to-point and publish-and-subscribe), reliability and security.</p> + + <subsection name="Layout"> + <p>This appender requires a layout. If no layout is specified in configuration, + <code><a href="../layouts/simple.html">LoggerLayoutSimple</a></code> will be used by default.</p> + </subsection> + + <subsection name="Parameters"> + <p>The following parameters are available:</p> + + <table> + <thead> + <tr> + <th>Parameter</th> + <th>Type</th> + <th>Required</th> + <th>Default</th> + <th>Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>host</td> + <td>string</td> + <td>No</td> + <td>localhost</td> + <td>Server on which AMQP instance is located.</td> + </tr> + <tr> + <td>port</td> + <td>integer</td> + <td>No</td> + <td>5672</td> + <td>Port on which the instance is bound.</td> + </tr> + <tr> + <td>vhost</td> + <td>string</td> + <td>No</td> + <td>/</td> + <td>The name of the "virtual host".</td> + </tr> + <tr> + <td>login</td> + <td>string</td> + <td>No</td> + <td>guest</td> + <td>Login used to connect to the AMQP server.</td> + </tr> + <tr> + <td>password</td> + <td>string</td> + <td>No</td> + <td>guest</td> + <td>Password used to connect to the AMQP server.</td> + </tr> + <tr> + <td>exchangeName</td> + <td>string</td> + <td>Yes</td> + <td>-</td> + <td>Name of AMQP exchange which used to routing logs.</td> + </tr> + <tr> + <td>exchangeType</td> + <td>string</td> + <td>No</td> + <td>direct</td> + <td>Type of AMQP exchange.</td> + </tr> + <tr> + <td>routingKey</td> + <td>string</td> + <td>Yes</td> + <td>-</td> + <td>Routing key which used to routing logs.</td> + </tr> + <tr> + <td>connectionTimeout</td> + <td>float</td> + <td>No</td> + <td>0.5</td> + <td>Connection timeout in seconds.</td> + </tr> + <tr> + <td>contentType</td> + <td>string</td> + <td>No</td> + <td>text/plain</td> + <td>Content-type header.</td> + </tr> + <tr> + <td>contentEncoding</td> + <td>string</td> + <td>No</td> + <td>UTF-8</td> + <td>Content-encoding header.</td> + </tr> + <tr> + <td>flushOnShutdown</td> + <td>boolean</td> + <td>No</td> + <td>false</td> + <td>Send logs immediately or stash it and send on shutdown.</td> + </tr> + </tbody> + </table> + </subsection> + + <subsection name="Examples"> + <p>This example shows how to configure <code>LoggerAppenderAMQP</code> to log to a remote server.</p> + + <div class="auto-tabs"> + <ul> + <li>XML</li> + <li>PHP</li> + </ul> + + <div class="tab-content" > + <div class="tab-pane"> + <pre class="prettyprint"><![CDATA[ +<configuration xmlns="http://logging.apache.org/log4php/"> + <appender name="default" class="LoggerAppenderAMQP"> + <param name="host" value="localhost" /> + <param name="port" value="5672" /> + <param name="vhost" value="/" /> + <param name="login" value="my_login" /> + <param name="password" value="my_secret_password" /> + <param name="exchangeName" value="my_exchange" /> + <param name="routingKey" value="php_application" /> + </appender> + <root> + <appender_ref ref="default" /> + </root> +</configuration> +]]></pre> + </div> + <div class="tab-pane"> + <pre class="prettyprint"><![CDATA[ +array( + 'appenders' => array( + 'default' => array( + 'class' => 'LoggerAppenderAMQP', + 'params' => array( + 'host' => 'localhost', + 'port' => 5672, + 'vhost' => '/', + 'login' => 'my_login', + 'password' => 'my_secret_password', + 'exchangeName' => 'my_exchange', + 'routingKey' => 'php_application', + ), + ), + ), + 'rootLogger' => array( + 'appenders' => array('default'), + ), +); +]]></pre> + </div> + </div> + </div> + </subsection> + </section> + </body> +</document> http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/c2930f29/src/test/php/appenders/LoggerAppenderAMQPTest.php ---------------------------------------------------------------------- diff --git a/src/test/php/appenders/LoggerAppenderAMQPTest.php b/src/test/php/appenders/LoggerAppenderAMQPTest.php new file mode 100644 index 0000000..4360ccc --- /dev/null +++ b/src/test/php/appenders/LoggerAppenderAMQPTest.php @@ -0,0 +1,281 @@ +<?php +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @category tests + * @package log4php + * @subpackage appenders + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 + * @link http://logging.apache.org/log4php + */ + +/** + * Testclass for the AMQP appender. + * + * This class has been originally contributed from Dmitry Ulyanov + * (http://github.com/d-ulyanov/log4php-graylog2). + * + * @group appenders + */ +class LoggerAppenderAMQPTest extends PHPUnit_Framework_TestCase { + + /** + * @var LoggerAppenderAMQP + */ + private $appender; + + private $config = array( + 'host' => 'localhost', + 'port' => 5672, + 'login' => 'guest', + 'password' => 'guest', + 'vhost' => '/logs', + 'exchangeName' => 'logs', + 'exchangeType' => 'direct', + 'contentEncoding' => 'UTF-8', + 'contentType' => 'application/json', + 'routingKey' => 'php_website', + 'flushOnShutdown' => 0, + 'connectionTimeout' => 0.5, + ); + + public function testRequiresLayout() { + $appender = new LoggerAppenderAMQP(); + $this->assertTrue($appender->requiresLayout()); + } + + protected function setUp() { + if (extension_loaded('amqp')) { + $this->appender = $this->createAppender(); + } else { + $this->markTestSkipped( + 'The amqp extension is not available.' + ); + } + } + + protected function tearDown() { + if (extension_loaded('amqp')) { + $this->appender = null; + } + } + + public function testHost() { + $expected = $this->config['host']; + $this->appender->setHost($expected); + $result = $this->appender->getHost(); + $this->assertEquals($expected, $result); + } + + public function testPort() { + $expected = $this->config['port']; + $this->appender->setPort($expected); + $result = $this->appender->getPort(); + $this->assertEquals($expected, $result); + } + + public function testLogin() { + $expected = $this->config['login']; + $this->appender->setLogin($expected); + $result = $this->appender->getLogin(); + $this->assertEquals($expected, $result); + } + + public function testPassword() { + $expected = $this->config['password']; + $this->appender->setPassword($expected); + $result = $this->appender->getPassword(); + $this->assertEquals($expected, $result); + } + + public function testVhost() { + $expected = $this->config['vhost']; + $this->appender->setVhost($expected); + $result = $this->appender->getVhost(); + $this->assertEquals($expected, $result); + } + + public function testExchangeName() { + $expected = $this->config['exchangeName']; + $this->appender->setExchangeName($expected); + $result = $this->appender->getExchangeName(); + $this->assertEquals($expected, $result); + } + + public function testExchangeType() { + $expected = $this->config['exchangeType']; + $this->appender->setExchangeType($expected); + $result = $this->appender->getExchangeType(); + $this->assertEquals($expected, $result); + } + + public function testRoutingKey() { + $expected = $this->config['routingKey']; + $this->appender->setRoutingKey($expected); + $result = $this->appender->getRoutingKey(); + $this->assertEquals($expected, $result); + } + + public function testContentEncoding() { + $expected = $this->config['contentEncoding']; + $this->appender->setContentEncoding($expected); + $result = $this->appender->getContentEncoding(); + $this->assertEquals($expected, $result); + } + + public function testFlushOnShutdown() { + $expected = $this->config['flushOnShutdown']; + $this->appender->setFlushOnShutdown($expected); + $result = $this->appender->getFlushOnShutdown(); + $this->assertEquals($expected, $result); + } + + public function testConnectionTimeout() { + $expected = $this->config['connectionTimeout']; + $this->appender->setConnectionTimeout($expected); + $result = $this->appender->getConnectionTimeout(); + $this->assertEquals($expected, $result); + } + + public function testActivateOptions() { + $mockAppender = $this->createMockAppender(array( + 'createAMQPConnection', + 'createAMQPExchange', + 'setAMQPConnection', + 'setAMQPExchange' + )); + + $AMQPEmptyConnection = new AMQPConnection; + + $mockAppender->expects($this->once()) + ->method('createAMQPConnection') + ->will($this->returnValue($AMQPEmptyConnection)); + + $AMQPExchangeMock = $this->getMockBuilder('AMQPExchange') + ->setMethods(null) + ->disableOriginalConstructor(); + + $mockAppender->expects($this->once()) + ->method('createAMQPExchange') + ->will($this->returnValue($AMQPExchangeMock)); + + $mockAppender->expects($this->once())->method('setAMQPConnection'); + $mockAppender->expects($this->once())->method('setAMQPExchange'); + + $mockAppender->activateOptions(); + } + + /** + * @expectedException PHPUnit_Framework_Error_Warning + */ + public function testActivateOptionsWithInvalidHost() { + $appender = $this->createPreparedAppender(); + $appender->setHost('unexpected-host.i'); + $appender->activateOptions(); + } + + public function testSendLogToAMQP() + { + $expected = "Some short log message"; + $AMQPExchangeMock = new LoggerAppenderAMQP_ExchangeStub; + + $mockAppender = $this->createMockAppender(array('getAMQPExchange')); + $mockAppender->expects($this->once()) + ->method('getAMQPExchange') + ->will($this->returnValue($AMQPExchangeMock)); + + $mockAppender->sendLogToAMQP($expected); + $this->assertEquals($expected, $AMQPExchangeMock->getLastMessage()); + } + + public function testStashLog() + { + $expected = "Some log message"; + $appender = $this->createAppender(); + $appender->stashLog($expected); + + $this->assertEquals(array($expected), PHPUnit_Framework_Assert::readAttribute($appender, 'logsStash')); + } + + public function testProcessLogWithoutStash() + { + $mockAppender = $this->createMockAppender(array('sendLogToAMQP')); + $mockAppender->expects($this->once())->method('sendLogToAMQP'); + $mockAppender->processLog("Some log message", 0); + } + + public function testProcessLogWitStash() + { + $mockAppender = $this->createMockAppender(array('stashLog')); + $mockAppender->expects($this->once())->method('stashLog'); + $mockAppender->processLog("Some log message", 1); + } + + public function testSendLogsArrayToAMQP() + { + $stashedLogs = array("One stashed log"); + $mockAppender = $this->createMockAppender(array('sendLogToAMQP')); + $mockAppender->expects($this->once())->method('sendLogToAMQP'); + $mockAppender->sendLogsArrayToAMQP($stashedLogs); + } + + private function createAppender() + { + return new LoggerAppenderAMQP('amqp_appender'); + } + + private function createPreparedAppender() + { + $appender = $this->createAppender(); + + foreach ($this->config as $option => $value) { + $setter = "set$option"; + $appender->$setter($value); + } + + return $appender; + } + + /** + * @param array $methods + * @return PHPUnit_Framework_MockObject_MockObject | LoggerAppenderAMQP + */ + private function createMockAppender(array $methods = array()) + { + return $this->getMock('LoggerAppenderAMQP', $methods); + } +} + +class LoggerAppenderAMQP_ExchangeStub +{ + protected $stash = array(); + + public function publish($message, $routing_key, $flags = AMQP_NOPARAM, array $attributes = array()) + { + $this->stash[] = $message; + return true; + } + + public function cleanStash() + { + $this->stash = array(); + } + + public function getLastMessage() + { + return array_pop($this->stash); + } +} \ No newline at end of file
