LOG4PHP-207: Using class MongoClient instead of Mongo - additional connection options support - support for replica tests - support for multiple hosts via connection string
Signed-off-by: Vladimir Gorej <[email protected]> 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/f6d602f4 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4php/tree/f6d602f4 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4php/diff/f6d602f4 Branch: refs/heads/develop Commit: f6d602f465dfb78aef67b196ac5456ff6c2b945f Parents: daf50b4 Author: Vladimir Gorej <[email protected]> Authored: Sun Mar 17 16:13:50 2013 +0100 Committer: Ivan Habunek <[email protected]> Committed: Mon Mar 18 08:09:41 2013 +0100 ---------------------------------------------------------------------- src/main/php/appenders/LoggerAppenderMongoDB.php | 318 ++++++++++++--- .../php/appenders/LoggerAppenderMongoDBTest.php | 81 ++++- 2 files changed, 338 insertions(+), 61 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/f6d602f4/src/main/php/appenders/LoggerAppenderMongoDB.php ---------------------------------------------------------------------- diff --git a/src/main/php/appenders/LoggerAppenderMongoDB.php b/src/main/php/appenders/LoggerAppenderMongoDB.php index 4963035..8fb1db0 100644 --- a/src/main/php/appenders/LoggerAppenderMongoDB.php +++ b/src/main/php/appenders/LoggerAppenderMongoDB.php @@ -15,25 +15,32 @@ * 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: ## - * + * + * - **connectionString ** - Connection string, if used host and port properties are ignored. Allows defining multiple hosts. * - **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). + * - **timeout** - DEPRECATED; For how long the driver should try to connect to the database (in milliseconds). + * - **connectionTimeout** - How long a connection can take to be opened before timing out. + * - **socketTimeout** - How long a send or receive on a socket can take before timing out. * - **capped** - Whether the collection should be a fixed size. * - **cappedMax** - If the collection is fixed size, the maximum number of elements to store in the collection. * - **cappedSize** - If the collection is fixed size, its size in bytes. - * + * - **writeConcern** - Controls how many nodes must acknowledge the write instruction before the driver continues. + * - **writeConcernJournaled** - The write will be acknowledged by primary and the journal flushed to disk. + * - **writeConcernTimeout** - Controls how many milliseconds the server waits for the write concern to be satisfied. + * - **replicaSet** - The name of the replica set to connect to. Primary will be automatically determined. + * * @package log4php * @subpackage appenders * @since 2.1 @@ -43,72 +50,92 @@ * @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} */ + + /** Default value for {@link $databaseName}. */ const DEFAULT_DB_NAME = 'log4php_mongodb'; - - /** Default value for {@link $collectionName} */ + + /** Default value for {@link $collectionName}. */ const DEFAULT_COLLECTION_NAME = 'logs'; - - /** Default value for {@link $timeout} */ + + /** Default value for {@link $timeout} + * @deprecated + */ const DEFAULT_TIMEOUT_VALUE = 3000; - /** Default value for {@link $capped} */ + /** Default value for {@link $capped}. */ const DEFAULT_CAPPED = false; - /** Default value for {@link $cappedMax} */ + /** Default value for {@link $cappedMax}. */ const DEFAULT_CAPPED_MAX = 1000; - /** Default value for {@link $cappedSize} */ + /** Default value for {@link $cappedSize}. */ const DEFAULT_CAPPED_SIZE = 1000000; - + + /** Single/Primary server acknowledgement of write operation. {@link $writeConcern}. */ + const WC_ACKNOWLEDGED = 1; + + /** Default value for {@link $writeConcernTimeout}. */ + const WC_TIMEOUT = 3000; + + /** + * Default value for {@link $writeConcernJournaled}. + */ + const WC_JOURNALED = false; + + // ****************************************** // ** Configurable parameters ** // ****************************************** - + + /** + * Support for multiple hosts and additional connection options. + * @var string + */ + protected $connectionString; + /** Server on which mongodb instance is located. * @var string */ protected $host; - + /** Port on which the instance is bound. * @var int */ protected $port; - + /** Name of the database to which to log. * @var string */ protected $databaseName; - + /** Name of the collection within the given database. * @var string */ protected $collectionName; - + /** Username used to connect to the database. * @var string */ protected $userName; - + /** Password used to connect to the database. * @var string */ protected $password; - + /** Timeout value used when connecting to the database (in milliseconds). * @var int */ @@ -128,7 +155,44 @@ class LoggerAppenderMongoDB extends LoggerAppender { * @var int */ protected $cappedSize; - + + /** + * How long the driver blocks when writing + * @var string + */ + protected $writeConcern; + + /** + * The write will be acknowledged by primary and the journal flushed to disk. + * @var bool + */ + protected $writeConcernJournaled; + + /** + * Write concern timeout in milliseconds. + * @var int + */ + protected $writeConcernTimeout; + + /** + * Connection timeout in milliseconds. + * @var int + */ + protected $connectionTimeout; + + /** + * Socket timeout in milliseconds. + * @var int + */ + protected $socketTimeout; + + /** + * Name of the replicaSet. + * @var string + */ + protected $replicaSet; + + // ****************************************** // ** Member variables ** // ****************************************** @@ -138,16 +202,22 @@ class LoggerAppenderMongoDB extends LoggerAppender { * @var Mongo */ protected $connection; - + /** * The collection to which log is written. * @var MongoCollection */ protected $collection; + /** + * Write options. + * @var array + */ + protected $writeOptions; + public function __construct($name = '') { parent::__construct($name); - $this->host = self::DEFAULT_MONGO_URL_PREFIX . self::DEFAULT_MONGO_HOST; + $this->host = self::DEFAULT_MONGO_HOST; $this->port = self::DEFAULT_MONGO_PORT; $this->databaseName = self::DEFAULT_DB_NAME; $this->collectionName = self::DEFAULT_COLLECTION_NAME; @@ -156,16 +226,49 @@ class LoggerAppenderMongoDB extends LoggerAppender { $this->capped = self::DEFAULT_CAPPED; $this->cappedMax = self::DEFAULT_CAPPED_MAX; $this->cappedSize = self::DEFAULT_CAPPED_SIZE; + $this->writeConcern = self::WC_ACKNOWLEDGED; + $this->writeConcernJournaled = self::WC_JOURNALED; + $this->writeConcernTimeout = self::WC_TIMEOUT; } - + /** * Setup db connection. * Based on defined options, this method connects to the database and * creates a {@link $collection}. */ public function activateOptions() { + # Building connection options. + $options = array( + 'w' => (is_numeric($this->writeConcern)) ? (int) $this->writeConcern : $this->writeConcern, + 'timeout' => $this->timeout, + 'wTimeout' => $this->writeConcernTimeout + ); + if ($this->replicaSet !== null) { + $options['replicaSet'] = $this->replicaSet; + } + if ($this->socketTimeout !== null) { + $options['socketTimeoutMS'] = $this->socketTimeout; + } + # Backwards compatibility with timeout parameter. + if ($this->connectionTimeout !== null) { + $options['connectTimeoutMS'] = $options['timeout'] = $this->connectionTimeout; + } + + # Building write options. + $this->writeOptions = array( + 'w' => (is_numeric($this->writeConcern)) ? (int) $this->writeConcern : $this->writeConcern, + 'j' => $this->writeConcernJournaled + ); + try { - $this->connection = new Mongo(sprintf('%s:%d', $this->host, $this->port), array('timeout' => $this->timeout)); + $clientClass = class_exists('MongoClient') ? 'MongoClient' : 'Mongo'; + # Connection string generation. + if ($this->connectionString === null) { + $connectionString = sprintf('%s%s:%d', self::DEFAULT_MONGO_URL_PREFIX, $this->host, $this->port); + } else { + $connectionString = $this->connectionString; + } + $this->connection = new $clientClass($connectionString, $options); $db = $this->connection->selectDB($this->databaseName); if ($this->userName !== null && $this->password !== null) { $authResult = $db->authenticate($this->userName, $this->password); @@ -175,7 +278,7 @@ class LoggerAppenderMongoDB extends LoggerAppender { } if ($this->capped === true) { $this->collection = $db->createCollection($this->collectionName, $this->capped, $this->cappedSize, - $this->cappedMax); + $this->cappedMax); } else { $this->collection = $db->selectCollection($this->collectionName); } @@ -199,13 +302,13 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function append(LoggerLoggingEvent $event) { try { if ($this->collection != null) { - $this->collection->insert($this->format($event)); + $this->collection->insert($this->format($event), $this->writeOptions); } } 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. * @@ -236,10 +339,10 @@ class LoggerAppenderMongoDB extends LoggerAppender { if ($throwableInfo != null) { $document['exception'] = $this->formatThrowable($throwableInfo->getThrowable()); } - + return $document; } - + /** * Converts an Exception into an array which can be logged to mongodb. * @@ -254,14 +357,14 @@ class LoggerAppenderMongoDB extends LoggerAppender { '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 */ @@ -275,18 +378,31 @@ class LoggerAppenderMongoDB extends LoggerAppender { $this->closed = true; } } - - /** + + /** + * Sets the value of {@link $connectionString}. + * @param string $connectionString + */ + public function setConnectionString($connectionString) { + $this->setString('connectionString', $connectionString); + } + + /** + * Returns the value of {@link $connectionString}. + * @return string + */ + public function getConnectionString() { + return $this->connectionString; + } + + /** * 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->setString('host', $host); } - + /** * Returns the value of {@link $host} parameter. * @return string @@ -302,7 +418,7 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function setPort($port) { $this->setPositiveInteger('port', $port); } - + /** * Returns the value of {@link $port} parameter. * @return int @@ -318,7 +434,7 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function setDatabaseName($databaseName) { $this->setString('databaseName', $databaseName); } - + /** * Returns the value of {@link $databaseName} parameter. * @return string @@ -334,7 +450,7 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function setCollectionName($collectionName) { $this->setString('collectionName', $collectionName); } - + /** * Returns the value of {@link $collectionName} parameter. * @return string @@ -350,7 +466,7 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function setUserName($userName) { $this->setString('userName', $userName, true); } - + /** * Returns the value of {@link $userName} parameter. * @return string @@ -366,7 +482,7 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function setPassword($password) { $this->setString('password', $password, true); } - + /** * Returns the value of {@link $password} parameter. * @return string @@ -375,8 +491,9 @@ class LoggerAppenderMongoDB extends LoggerAppender { return $this->password; } - /** + /** * Sets the value of {@link $timeout} parameter. + * @deprecated Use {@link $connectionTimeout} and {@link $socketTimeout} instead. * @param int $timeout */ public function setTimeout($timeout) { @@ -385,6 +502,7 @@ class LoggerAppenderMongoDB extends LoggerAppender { /** * Returns the value of {@link $timeout} parameter. + * @deprecated Use {@link $connectionTimeout} and {@link $socketTimeout} instead. * @return int */ public function getTimeout() { @@ -440,13 +558,109 @@ class LoggerAppenderMongoDB extends LoggerAppender { } /** + * Sets the value of {@link $writeConcern} parameter. + * @param string $writeConcern + */ + public function setWriteConcern($writeConcern) { + $this->setString('writeConcern', $writeConcern); + } + + /** + * Returns the value of {@link $writeConcern} parameter. + * @return string + */ + public function getWriteConcern() { + return $this->writeConcern; + } + + /** + * Sets the value of {@link $writeConcernJournaled} parameter. + * @param bool $writeConcernJournaled + */ + public function setWriteConcernJournaled($writeConcernJournaled) { + $this->setBoolean('writeConcernJournaled', $writeConcernJournaled); + } + + /** + * Returns the value of {@link $writeConcernJournaled} parameter. + * @return bool + */ + public function getWriteConcernJournaled() { + return $this->writeConcernJournaled; + } + + /** + * Sets the value of {@link $writeConcernTimeout} parameter. + * @param int $writeConcernTimeout + */ + public function setWriteConcernTimeout($writeConcernTimeout) { + $this->setPositiveInteger('writeConcernTimeout', $writeConcernTimeout); + } + + /** + * Returns the value of {@link $writeConcernTimeout} parameter. + * @return int + */ + public function getWriteConcernTimeout() { + return $this->writeConcernTimeout; + } + + /** + * Sets the value of {@link $connectionTimeout} parameter. + * @param int $connectionTimeout + */ + public function setConnectionTimeout($connectionTimeout) { + $this->setPositiveInteger('connectionTimeout', $connectionTimeout); + } + + /** + * Returns the value of {@link $connectionTimeout} parameter. + * @return int + */ + public function getConnectionTimeout() { + return $this->connectionTimeout; + } + + /** + * Sets the value of {@link $socketTimeout} parameter. + * @param int $socketTimeout + */ + public function setSocketTimeout($socketTimeout) { + $this->setPositiveInteger('socketTimeout', $socketTimeout); + } + + /** + * Returns the value of {@link $socketTimeout} parameter. + * @return int + */ + public function getSocketTimeout() { + return $this->socketTimeout; + } + + /** + * Sets the value of {@link $replicaSet} parameter. + * @param string $replicaSet + */ + public function setReplicaSet($replicaSet) { + $this->setString('replicaSet', $replicaSet); + } + + /** + * Returns the value of {@link $replicaSet} parameter. + * @return string + */ + public function getReplicaSet() { + return $this->replicaSet; + } + + /** * Returns the mongodb connection. * @return Mongo */ public function getConnection() { return $this->connection; } - + /** * Returns the active mongodb collection. * @return MongoCollection @@ -454,4 +668,4 @@ class LoggerAppenderMongoDB extends LoggerAppender { public function getCollection() { return $this->collection; } -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/logging-log4php/blob/f6d602f4/src/test/php/appenders/LoggerAppenderMongoDBTest.php ---------------------------------------------------------------------- diff --git a/src/test/php/appenders/LoggerAppenderMongoDBTest.php b/src/test/php/appenders/LoggerAppenderMongoDBTest.php index fe7a62c..3be6c9c 100644 --- a/src/test/php/appenders/LoggerAppenderMongoDBTest.php +++ b/src/test/php/appenders/LoggerAppenderMongoDBTest.php @@ -31,12 +31,12 @@ * @group appenders */ class LoggerAppenderMongoDBTest extends PHPUnit_Framework_TestCase { - + protected $appender; protected $event; - + protected function setUp() { - if (!extension_loaded('mongo')) { + if (!extension_loaded('Mongo')) { $this->markTestSkipped( 'The Mongo extension is not available.' ); @@ -54,7 +54,14 @@ class LoggerAppenderMongoDBTest extends PHPUnit_Framework_TestCase { } unset($this->appender); } - + + public function testConnectionString() { + $expected = 'mongodb://localhost,localhost'; + $this->appender->setConnectionString($expected); + $result = $this->appender->getConnectionString(); + $this->assertEquals($expected, $result); + } + public function testHost() { $expected = 'mongodb://localhost'; $this->appender->setHost($expected); @@ -125,9 +132,52 @@ class LoggerAppenderMongoDBTest extends PHPUnit_Framework_TestCase { $this->assertEquals($expected, $result); } + public function testWriteConcern() { + $expected = 7; + $this->appender->setWriteConcern($expected); + $result = $this->appender->getWriteConcern(); + $this->assertEquals($expected, $result); + } + + public function testWriteConcernJournaled() { + $expected = true; + $this->appender->setWriteConcernJournaled($expected); + $result = $this->appender->getWriteConcernJournaled(); + $this->assertEquals($expected, $result); + } + + + public function testWriteConcernTimeout() { + $expected = 100; + $this->appender->setWriteConcernTimeout($expected); + $result = $this->appender->getWriteConcernTimeout(); + $this->assertEquals($expected, $result); + } + + public function testConnectionTimeout() { + $expected = 200; + $this->appender->setConnectionTimeout($expected); + $result = $this->appender->getConnectionTimeout(); + $this->assertEquals($expected, $result); + } + + public function testSocketTimeout() { + $expected = 300; + $this->appender->setSocketTimeout($expected); + $result = $this->appender->getSocketTimeout(); + $this->assertEquals($expected, $result); + } + + public function testReplicaSet() { + $expected = 'replica_set'; + $this->appender->setReplicaSet($expected); + $result = $this->appender->getReplicaSet(); + $this->assertEquals($expected, $result); + } + public function testActivateOptions() { $this->appender->activateOptions(); - $this->assertInstanceOf('Mongo', $this->appender->getConnection()); + $this->assertInstanceOf('MongoClient', $this->appender->getConnection()); $this->assertInstanceOf('MongoCollection', $this->appender->getCollection()); } @@ -135,7 +185,7 @@ class LoggerAppenderMongoDBTest extends PHPUnit_Framework_TestCase { $this->appender->setUserName(null); $this->appender->setPassword(null); $this->appender->activateOptions(); - $this->assertInstanceOf('Mongo', $this->appender->getConnection()); + $this->assertInstanceOf('MongoClient', $this->appender->getConnection()); $this->assertInstanceOf('MongoCollection', $this->appender->getCollection()); } @@ -143,7 +193,7 @@ class LoggerAppenderMongoDBTest extends PHPUnit_Framework_TestCase { $this->appender->setCollectionName('logs_capped'); $this->appender->setCapped(true); $this->appender->activateOptions(); - $this->assertInstanceOf('Mongo', $this->appender->getConnection()); + $this->assertInstanceOf('MongoClient', $this->appender->getConnection()); $this->assertInstanceOf('MongoCollection', $this->appender->getCollection()); } @@ -227,9 +277,22 @@ class LoggerAppenderMongoDBTest extends PHPUnit_Framework_TestCase { $this->assertEquals($expected, $this->appender->getCollection()->count()); } + /** + * @expectedException PHPUnit_Framework_Error + */ + public function testReplicaSetOption() { + $this->appender->setReplicaSet('mongo_appender_replica_set1'); + $this->appender->activateOptions(); + } + + public function testMultipleHostsConnection() { + $this->appender->setConnectionString('mongodb://locahost:27017,localhost:27017'); + $this->appender->activateOptions(); + } + public function testClose() { $this->appender->activateOptions(); - $this->assertInstanceOf('Mongo', $this->appender->getConnection()); + $this->assertInstanceOf('MongoClient', $this->appender->getConnection()); $this->assertInstanceOf('MongoCollection', $this->appender->getCollection()); $this->appender->close(); $this->assertNull($this->appender->getConnection()); @@ -250,4 +313,4 @@ class LoggerAppenderMongoDBTest extends PHPUnit_Framework_TestCase { $this->assertNotNull($record, 'Could not read the record from the database.'); return $record; } -} +} \ No newline at end of file
