diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..5dc7290c5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# CHANGELOG + + +## 1.18.0 (unreleased) + + * Add `addSubscriber` and `removeSubscriber` methods to the `Client` class to ease dependency injection configuration + diff --git a/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml b/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml new file mode 100644 index 000000000..27de61506 --- /dev/null +++ b/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml @@ -0,0 +1,9 @@ +arg_name: param +name: $subscriber +type: :php:`MongoDB\\Driver\\Monitoring\\Subscriber ` +description: | + A monitoring event subscriber to register with this Client. +interface: phpmethod +operation: ~ +optional: false +... diff --git a/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml b/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml new file mode 100644 index 000000000..eaeec4fdf --- /dev/null +++ b/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml @@ -0,0 +1,9 @@ +arg_name: param +name: $subscriber +type: :php:`MongoDB\\Driver\\Monitoring\\Subscriber ` +description: | + A monitoring event subscriber to unregister with this Client. +interface: phpmethod +operation: ~ +optional: false +... diff --git a/docs/reference/class/MongoDBClient.txt b/docs/reference/class/MongoDBClient.txt index b677ebb1d..654a474a5 100644 --- a/docs/reference/class/MongoDBClient.txt +++ b/docs/reference/class/MongoDBClient.txt @@ -30,6 +30,7 @@ Methods /reference/method/MongoDBClient__construct /reference/method/MongoDBClient__get + /reference/method/MongoDBClient-addSubscriber /reference/method/MongoDBClient-createClientEncryption /reference/method/MongoDBClient-dropDatabase /reference/method/MongoDBClient-getManager @@ -39,6 +40,7 @@ Methods /reference/method/MongoDBClient-getWriteConcern /reference/method/MongoDBClient-listDatabaseNames /reference/method/MongoDBClient-listDatabases + /reference/method/MongoDBClient-removeSubscriber /reference/method/MongoDBClient-selectCollection /reference/method/MongoDBClient-selectDatabase /reference/method/MongoDBClient-startSession diff --git a/docs/reference/method/MongoDBClient-addSubscriber.txt b/docs/reference/method/MongoDBClient-addSubscriber.txt new file mode 100644 index 000000000..e55a94841 --- /dev/null +++ b/docs/reference/method/MongoDBClient-addSubscriber.txt @@ -0,0 +1,132 @@ +================================ +MongoDB\\Client::addSubscriber() +================================ + +.. versionadded:: 1.18 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::addSubscriber() + + Registers a monitoring event subscriber with this Client. The subscriber + will be notified of all events for this Client. + + .. code-block:: php + + function addSubscriber(MongoDB\Driver\Monitoring\Subscriber $subscriber): void + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-addSubscriber-param.rst + + .. note:: + + If ``$subscriber`` is already registered with this Client, this function + is a no-op. If ``$subscriber`` is also registered globally, it will still + only be notified once of each event for this Client. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +:php:`MongoDB\\Driver\\Exception\\InvalidArgumentException ` +if subscriber is a :php:`MongoDB\\Driver\\Monitoring\\LogSubscriber `, +since loggers can only be registered globally with +:php:`MongoDB\\Driver\\Monitoring\\addSubscriber `. + +Example +------- + +Create a :phpclass:`MongoDB\\Driver\\Monitoring\\CommandSubscriber` that +logs all events: + +.. code-block:: php + + stream = $stream; + } + + public function commandStarted(CommandStartedEvent $event): void + { + fwrite($this->stream, sprintf( + 'Started command #%d "%s": %s%s', + $event->getRequestId(), + $event->getCommandName(), + Document::fromPHP($event->getCommand())->toCanonicalExtendedJSON(), + PHP_EOL, + )); + } + + public function commandSucceeded(CommandSucceededEvent $event): void + { + fwrite($this->stream, sprintf( + 'Succeeded command #%d "%s" in %d microseconds: %s%s', + $event->getRequestId(), + $event->getCommandName(), + $event->getDurationMicros(), + json_encode($event->getReply()), + PHP_EOL, + )); + } + + public function commandFailed(CommandFailedEvent $event): void + { + fwrite($this->stream, sprintf( + 'Failed command #%d "%s" in %d microseconds: %s%s', + $event->getRequestId(), + $event->getCommandName(), + $event->getDurationMicros(), + $event->getError()->getMessage(), + PHP_EOL, + )); + } + } + +The subscriber can then be registered with a Client: + +.. code-block:: php + + addSubscriber($subscriber); + + $client->test->users->insertOne(['username' => 'alice']); + +The above code will write the following to stderr output: + +.. code-block:: text + + Started command #1 "insert": { "insert" : "users", "ordered" : true, "$db" : "test", "lsid" : { "id" : { "$binary" : { "base64" : "dKTBhZD7Qvi0vUhvR58mCA==", "subType" : "04" } } }, "documents" : [ { "username" : "alice", "_id" : { "$oid" : "655d1fca12e81018340a4fc2" } } ] } + Succeeded command #1 "insert" in 876 microseconds: {"n":1,"ok":1} + +See Also +-------- + +- :phpmethod:`MongoDB\\Client::removeSubscriber()` +- :php:`Application Performance Monitoring (APM) ` +- :php:`MongoDB\\Driver\\Manager::addSubscriber() ` +- :php:`MongoDB\Driver\Monitoring\CommandSubscriber ` diff --git a/docs/reference/method/MongoDBClient-removeSubscriber.txt b/docs/reference/method/MongoDBClient-removeSubscriber.txt new file mode 100644 index 000000000..28e7e6d96 --- /dev/null +++ b/docs/reference/method/MongoDBClient-removeSubscriber.txt @@ -0,0 +1,46 @@ +================================ +MongoDB\\Client::removeSubscriber() +================================ + +.. versionadded:: 1.18 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Client::removeSubscriber() + + Unregisters a monitoring event subscriber with this Client. + + .. code-block:: php + + function removeSubscriber(MongoDB\Driver\Monitoring\Subscriber $subscriber): void + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBClient-method-removeSubscriber-param.rst + + .. note:: + + If ``$subscriber`` is not registered with this Client, this function + is a no-op. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-invalidargumentexception.rst + +See Also +-------- + +- :phpmethod:`MongoDB\\Client::addSubscriber()` +- :php:`Application Performance Monitoring (APM) ` +- :php:`MongoDB\\Driver\\Manager::removeSubscriber() ` +- :php:`MongoDB\Driver\Monitoring\CommandSubscriber ` diff --git a/examples/command_logger.php b/examples/command_logger.php index d3f007bbc..790c09a67 100644 --- a/examples/command_logger.php +++ b/examples/command_logger.php @@ -56,7 +56,7 @@ public function commandFailed(CommandFailedEvent $event): void $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); -$client->getManager()->addSubscriber(new CommandLogger()); +$client->addSubscriber(new CommandLogger()); $collection = $client->test->command_logger; $collection->drop(); diff --git a/src/Client.php b/src/Client.php index acdeef003..429b75099 100644 --- a/src/Client.php +++ b/src/Client.php @@ -23,6 +23,7 @@ use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException; use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\Manager; +use MongoDB\Driver\Monitoring\Subscriber; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Session; @@ -163,6 +164,16 @@ public function __toString() return $this->uri; } + /** + * Registers a monitoring event subscriber with this Client's Manager + * + * @see Manager::addSubscriber() + */ + final public function addSubscriber(Subscriber $subscriber): void + { + $this->manager->addSubscriber($subscriber); + } + /** * Returns a ClientEncryption instance for explicit encryption and decryption * @@ -296,6 +307,16 @@ public function listDatabases(array $options = []) return $operation->execute($server); } + /** + * Unregisters a monitoring event subscriber with this Client's Manager + * + * @see Manager::removeSubscriber() + */ + final public function removeSubscriber(Subscriber $subscriber): void + { + $this->manager->removeSubscriber($subscriber); + } + /** * Select a collection. * diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index e2be0f8ff..adbc0e531 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -4,7 +4,9 @@ use MongoDB\Client; use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\Command; use MongoDB\Driver\Manager; +use MongoDB\Driver\Monitoring\CommandSubscriber; use MongoDB\Driver\Session; use MongoDB\Model\DatabaseInfo; use MongoDB\Model\DatabaseInfoIterator; @@ -119,4 +121,20 @@ public function testStartSession(): void { $this->assertInstanceOf(Session::class, $this->client->startSession()); } + + public function testAddAndRemoveSubscriber(): void + { + $client = new Client(static::getUri()); + + $addedSubscriber = $this->createMock(CommandSubscriber::class); + $addedSubscriber->expects($this->once())->method('commandStarted'); + $client->addSubscriber($addedSubscriber); + + $removedSubscriber = $this->createMock(CommandSubscriber::class); + $removedSubscriber->expects($this->never())->method('commandStarted'); + $client->addSubscriber($removedSubscriber); + $client->removeSubscriber($removedSubscriber); + + $client->getManager()->executeCommand('admin', new Command(['ping' => 1])); + } }