<?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. *//** * Appender for writing to MongoDB. * * This class was originally contributed by Vladimir Gorej. * * ## Configurable parameters: ## * * - **host** - Server on which mongodb instance is located. * - **port** - Port on which the instance is bound. * - **databaseName** - Name of the database to which to log. * - **collectionName** - Name of the target collection within the given database. * - **username** - Username used to connect to the database. * - **password** - Password used to connect to the database. * - **timeout** - For how long the driver should try to connect to the database (in milliseconds). * * @version $Revision: 1346363 $ * @package log4php * @subpackage appenders * @since 2.1 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 * @link http://logging.apache.org/log4php/docs/appenders/mongodb.html Appender documentation * @link http://github.com/log4mongo/log4mongo-php Vladimir Gorej's original submission. * @link http://www.mongodb.org/ MongoDB website. */class LoggerAppenderMongoDB extends LoggerAppender { // ****************************************** // ** Constants ** // ****************************************** /** Default prefix for the {@link $host}. */ const DEFAULT_MONGO_URL_PREFIX = 'mongodb://'; /** Default value for {@link $host}, without a prefix. */ const DEFAULT_MONGO_HOST = 'localhost'; /** Default value for {@link $port} */ const DEFAULT_MONGO_PORT = 27017; /** Default value for {@link $databaseName} */ const DEFAULT_DB_NAME = 'log4php_mongodb'; /** Default value for {@link $collectionName} */ const DEFAULT_COLLECTION_NAME = 'logs'; /** Default value for {@link $timeout} */ const DEFAULT_TIMEOUT_VALUE = 3000; // ****************************************** // ** Configurable parameters ** // ****************************************** /** Server on which mongodb instance is located. */ protected $host; /** Port on which the instance is bound. */ protected $port; /** Name of the database to which to log. */ protected $databaseName; /** Name of the collection within the given database. */ protected $collectionName; /** Username used to connect to the database. */ protected $userName; /** Password used to connect to the database. */ protected $password; /** Timeout value used when connecting to the database (in milliseconds). */ protected $timeout; // ****************************************** // ** Member variables ** // ****************************************** /** * Connection to the MongoDB instance. * @var Mongo */ protected $connection; /** * The collection to which log is written. * @var MongoCollection */ protected $collection; public function __construct($name = '') { parent::__construct($name); $this->host = self::DEFAULT_MONGO_URL_PREFIX . self::DEFAULT_MONGO_HOST; $this->port = self::DEFAULT_MONGO_PORT; $this->databaseName = self::DEFAULT_DB_NAME; $this->collectionName = self::DEFAULT_COLLECTION_NAME; $this->timeout = self::DEFAULT_TIMEOUT_VALUE; $this->requiresLayout = false; } /** * Setup db connection. * Based on defined options, this method connects to the database and * creates a {@link $collection}. */ public function activateOptions() { try { $this->connection = new Mongo(sprintf('%s:%d', $this->host, $this->port), array('timeout' => $this->timeout)); $db = $this->connection->selectDB($this->databaseName); if ($this->userName !== null && $this->password !== null) { $authResult = $db->authenticate($this->userName, $this->password); if ($authResult['ok'] == floatval(0)) { throw new Exception($authResult['errmsg'], $authResult['ok']); } } $this->collection = $db->selectCollection($this->collectionName); } catch (MongoConnectionException $ex) { $this->closed = true; $this->warn(sprintf('Failed to connect to mongo deamon: %s', $ex->getMessage())); } catch (InvalidArgumentException $ex) { $this->closed = true; $this->warn(sprintf('Error while selecting mongo database: %s', $ex->getMessage())); } catch (Exception $ex) { $this->closed = true; $this->warn('Invalid credentials for mongo database authentication'); } } /** * Appends a new event to the mongo database. * * @param LoggerLoggingEvent $event */ public function append(LoggerLoggingEvent $event) { try { if ($this->collection != null) { $this->collection->insert($this->format($event)); } } catch (MongoCursorException $ex) { $this->warn(sprintf('Error while writing to mongo collection: %s', $ex->getMessage())); } } /** * Converts the logging event into an array which can be logged to mongodb. * * @param LoggerLoggingEvent $event * @return array The array representation of the logging event. */ protected function format(LoggerLoggingEvent $event) { $timestampSec = (int)$event->getTimestamp(); $timestampUsec = (int)(($event->getTimestamp() - $timestampSec) * 1000000); $document = array( 'timestamp' => new MongoDate($timestampSec, $timestampUsec), 'level' => $event->getLevel()->toString(), 'thread' => (int)$event->getThreadName(), 'message' => $event->getMessage(), 'loggerName' => $event->getLoggerName() ); $locationInfo = $event->getLocationInformation(); if ($locationInfo != null) { $document['fileName'] = $locationInfo->getFileName(); $document['method'] = $locationInfo->getMethodName(); $document['lineNumber'] = ($locationInfo->getLineNumber() == 'NA') ? 'NA' : (int)$locationInfo->getLineNumber(); $document['className'] = $locationInfo->getClassName(); } $throwableInfo = $event->getThrowableInformation(); if ($throwableInfo != null) { $document['exception'] = $this->formatThrowable($throwableInfo->getThrowable()); } return $document; } /** * Converts an Exception into an array which can be logged to mongodb. * * Supports innner exceptions (PHP >= 5.3) * * @param Exception $ex * @return array */ protected function formatThrowable(Exception $ex) { $array = array( 'message' => $ex->getMessage(), 'code' => $ex->getCode(), 'stackTrace' => $ex->getTraceAsString(), ); if (method_exists($ex, 'getPrevious') && $ex->getPrevious() !== null) { $array['innerException'] = $this->formatThrowable($ex->getPrevious()); } return $array; } /** * Closes the connection to the logging database */ public function close() { if ($this->closed != true) { $this->collection = null; if ($this->connection !== null) { $this->connection->close(); $this->connection = null; } $this->closed = true; } } /** * Sets the value of {@link $host} parameter. * @param string $host */ public function setHost($host) { if (!preg_match('/^mongodb\:\/\//', $host)) { $host = self::DEFAULT_MONGO_URL_PREFIX . $host; } $this->host = $host; } /** * Returns the value of {@link $host} parameter. * @return string */ public function getHost() { return $this->host; } /** * Sets the value of {@link $port} parameter. * @param int $port */ public function setPort($port) { $this->setPositiveInteger('port', $port); } /** * Returns the value of {@link $port} parameter. * @return int */ public function getPort() { return $this->port; } /** * Sets the value of {@link $databaseName} parameter. * @param string $databaseName */ public function setDatabaseName($databaseName) { $this->setString('databaseName', $databaseName); } /** * Returns the value of {@link $databaseName} parameter. * @return string */ public function getDatabaseName() { return $this->databaseName; } /** * Sets the value of {@link $collectionName} parameter. * @param string $collectionName */ public function setCollectionName($collectionName) { $this->setString('collectionName', $collectionName); } /** * Returns the value of {@link $collectionName} parameter. * @return string */ public function getCollectionName() { return $this->collectionName; } /** * Sets the value of {@link $userName} parameter. * @param string $userName */ public function setUserName($userName) { $this->setString('userName', $userName, true); } /** * Returns the value of {@link $userName} parameter. * @return string */ public function getUserName() { return $this->userName; } /** * Sets the value of {@link $password} parameter. * @param string $password */ public function setPassword($password) { $this->setString('password', $password, true); } /** * Returns the value of {@link $password} parameter. * @return string */ public function getPassword() { return $this->password; } /** * Sets the value of {@link $timeout} parameter. * @param int $timeout */ public function setTimeout($timeout) { $this->setPositiveInteger('timeout', $timeout); } /** * Returns the value of {@link $timeout} parameter. * @return int */ public function getTimeout() { return $this->timeout; } /** * Returns the mongodb connection. * @return Mongo */ public function getConnection() { return $this->connection; } /** * Returns the active mongodb collection. * @return MongoCollection */ public function getCollection() { return $this->collection; }}