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

Reply via email to