diff --git a/src/main/php/appenders/LoggerAppenderMongoDB.php b/src/main/php/appenders/LoggerAppenderMongoDB.php index c0f2c2d..14a7800 100644 --- a/src/main/php/appenders/LoggerAppenderMongoDB.php +++ b/src/main/php/appenders/LoggerAppenderMongoDB.php @@ -30,6 +30,9 @@ * - **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). + * - **writeConcern** - What the driver should wait for when writing to the database (if supported). + * - **writeConcernTimeout** - How long the driver should wait to satisfy the writeConcern (if supported). + * - **replicaSet** - The name of the replica set to connect to (if any). * * @version $Revision$ * @package log4php @@ -49,12 +52,6 @@ class LoggerAppenderMongoDB extends LoggerAppender { /** 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'; @@ -64,6 +61,16 @@ class LoggerAppenderMongoDB extends LoggerAppender { /** Default value for {@link $timeout} */ const DEFAULT_TIMEOUT_VALUE = 3000; + /** Write concern constants **/ + const WC_UNACKNOWLEDGED = '0'; + + const WC_ACKNOWLEDGED = '1'; + + const WC_REPLICA_SET = '3'; + + const WC_MAJORITY = 'majority'; + + // ****************************************** // ** Configurable parameters ** // ****************************************** @@ -88,6 +95,21 @@ class LoggerAppenderMongoDB extends LoggerAppender { /** Timeout value used when connecting to the database (in milliseconds). */ protected $timeout; + + /** + * @var string The name of the replica set + */ + protected $replica_set; + + /** + * @var string The write concern to be used by the driver (if supported) + */ + protected $write_concern; + + /** + * @var int The write concern timeout to be used by the driver (if supported) + */ + protected $write_concern_timeout; // ****************************************** // ** Member variables ** @@ -107,11 +129,13 @@ class LoggerAppenderMongoDB extends LoggerAppender { 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->host = self::DEFAULT_MONGO_URL_PREFIX . ini_get('mongo.default_host'); + $this->port = ini_get('mongo_default_port'); $this->databaseName = self::DEFAULT_DB_NAME; $this->collectionName = self::DEFAULT_COLLECTION_NAME; $this->timeout = self::DEFAULT_TIMEOUT_VALUE; + $this->write_concern = self::WC_UNACKNOWLEDGED; + $this->write_concern_timeout = self::DEFAULT_TIMEOUT_VALUE; $this->requiresLayout = false; } @@ -122,18 +146,12 @@ class LoggerAppenderMongoDB extends LoggerAppender { */ public function activateOptions() { try { - $this->connection = new Mongo(sprintf('%s:%d', $this->host, $this->port), array('timeout' => $this->timeout)); + $this->makeConnection(); $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())); + $this->warn(sprintf('Failed to connect to mongo daemon: %s', $ex->getMessage())); } catch (InvalidArgumentException $ex) { $this->closed = true; $this->warn(sprintf('Error while selecting mongo database: %s', $ex->getMessage())); @@ -168,11 +186,20 @@ class LoggerAppenderMongoDB extends LoggerAppender { $timestampSec = (int) $event->getTimestamp(); $timestampUsec = (int) (($event->getTimestamp() - $timestampSec) * 1000000); + $eventMessage = $event->getMessage(); + $messageArray = json_decode($eventMessage,true); + if ((is_array($messageArray)) && (!empty($messageArray))) { + $message = $messageArray; + } + else { + $message = $eventMessage; + } + $document = array( 'timestamp' => new MongoDate($timestampSec, $timestampUsec), 'level' => $event->getLevel()->toString(), 'thread' => (int) $event->getThreadName(), - 'message' => $event->getMessage(), + 'message' => $message, 'loggerName' => $event->getLoggerName() ); @@ -233,9 +260,6 @@ class LoggerAppenderMongoDB extends LoggerAppender { * @param string $host */ public function setHost($host) { - if (!preg_match('/^mongodb\:\/\//', $host)) { - $host = self::DEFAULT_MONGO_URL_PREFIX . $host; - } $this->host = $host; } @@ -357,4 +381,123 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function getCollection() { return $this->collection; } + + + /** + * Returns the write concern to be used by the driver + * @return string The write concern + */ + + public function getWriteConcern() { + return($this->write_concern); + } + + /** + * Sets the value of {@link $write_concern} parameter. + * @param string $val The value of the write concern (use class constants) + */ + public function setWriteConcern($val) { + $this->setString('write_concern', $val, true); + } + + /** + * Returns the write concern timeout to be used by the driver + * @return int The write concern timeout + */ + + public function getWriteConcernTimeout() { + return($this->write_concern_timeout); + } + + /** + * Sets the value of {@link $write_concern_timeout} parameter. + * @param int $val The value of the write concern timeout + */ + public function setWriteConcernTimeout($val) { + $this->setInteger('write_concern_timeout', $val); + } + + /** + * Returns the replica set for the connection + * @return string The replica set name + */ + + public function getReplicaSet() { + return($this->replica_set); + } + + /** + * Sets the value of {@link $replica_set} parameter. + * @param string $val The name of the replica set + */ + public function setReplicaSet($val) { + $this->setString('replica_set', $val, true); + } + + + /** + * Makes the database connection using the currently installed driver + * by building a connection string from the configuration parameters + * and sets the connection member variable + */ + protected function makeConnection() { + $options = array('timeout' => $this->timeout); + $host_string = ''; + $matches = array(); + $connect_pattern = '/(mongodb:\/\/)?(([^:]+):([^@]+)@)?([a-z0-9\_\-\.]+)(:\d+)?((,[a-z0-9\_\-\.]+)(:\d+)?)?((,[a-z0-9\_\-\.]+)(:\d+)?)?(\/[^\?]+)?(\?.+)?/i'; + if (preg_match($connect_pattern,$this->host,$matches)) { + $matches = array_pad($matches,15,''); + if (empty($matches[1])) { + $matches[1] = self::DEFAULT_MONGO_URL_PREFIX; + } + if (empty($matches[5])) { + $matches[5] = $this->host; + } + if ((empty($matches[6])) && (!empty($this->port))) { + $matches[6] = ':'.$this->port; + } + if (empty($matches[2])) { + if (!empty($this->userName)) { + $matches[2] = $this->userName; + if (!empty($this->password)) { + $matches[2] .= ':'.$this->password.'@'; + } + } + } + if (empty($matches[13])) { + $matches[13] = '/'.$this->databaseName; + } + $host_string = $matches[1].$matches[2].$matches[5].$matches[6]; + $host_string .= $matches[7].$matches[10]; + $host_string .= $matches[13].$matches[14]; + } + else { + $host_string = self::DEFAULT_MONGO_URL_PREFIX; + $host_string .= $this->host; + $host_string .= (!empty($this->port)) ? ':'.$this->port : ''; + $host_string .= '/'.$this->databaseName; + if (!empty($this->userName)) { + $options['username'] = $this->userName; + $options['password'] = $this->password; + } + } + + if (!empty($this->replica_set)) { + $options['replicaSet'] = $this->getReplicaSet(); + } + if (class_exists('MongoClient',false)) { + $options['w'] = $this->getWriteConcern(); + $write_concern_timeout = (int) $this->getWriteConcernTimeout(); + if ((is_integer($write_concern_timeout)) && ($write_concern_timeout > 0)) { + $options['wTimeout'] = $write_concern_timeout; + } + $this->connection = new MongoClient($host_string, $options); + } + elseif (class_exists('Mongo',false)) { + $this->connection = new Mongo($host_string,$options); + } + else { + throw new InvalidArgumentException('Neither Mongo nor MongoClient classes were found'); + } + } }