From 167bf9a1461ae2b32231d47290d1a6ad6cb7e902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 21 Nov 2023 12:01:23 +0100 Subject: [PATCH 1/4] PHPLIB-1309 Add addSubscriber/removeSubscriber to Client class to ease configuration --- CHANGELOG.md | 7 +++++++ src/Client.php | 21 +++++++++++++++++++++ tests/ClientFunctionalTest.php | 18 ++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 CHANGELOG.md 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/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])); + } } From 0361e4288f284738084a292c296276111c009727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 21 Nov 2023 22:00:05 +0100 Subject: [PATCH 2/4] Add documentation --- ...goDBClient-method-addSubscriber-param.yaml | 9 ++ ...BClient-method-removeSubscriber-param.yaml | 9 ++ docs/reference/class/MongoDBClient.txt | 2 + .../method/MongoDBClient-addSubscriber.txt | 130 ++++++++++++++++++ .../method/MongoDBClient-removeSubscriber.txt | 49 +++++++ 5 files changed, 199 insertions(+) create mode 100644 docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml create mode 100644 docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml create mode 100644 docs/reference/method/MongoDBClient-addSubscriber.txt create mode 100644 docs/reference/method/MongoDBClient-removeSubscriber.txt 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..22c9fb09c --- /dev/null +++ b/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml @@ -0,0 +1,9 @@ +arg_name: param +name: $subscriber +type: 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..22c9fb09c --- /dev/null +++ b/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml @@ -0,0 +1,9 @@ +arg_name: param +name: $subscriber +type: MongoDB\Driver\Monitoring\Subscriber +description: | + A monitoring event subscriber to register 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..9102b852f --- /dev/null +++ b/docs/reference/method/MongoDBClient-addSubscriber.txt @@ -0,0 +1,130 @@ +================================ +MongoDB\\Client::addSubscriber() +================================ + +.. 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 + +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 log the following to err 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 3349 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\Subscriber + ` +- :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..2b2249b87 --- /dev/null +++ b/docs/reference/method/MongoDBClient-removeSubscriber.txt @@ -0,0 +1,49 @@ +================================ +MongoDB\\Client::removeSubscriber() +================================ + +.. 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\Subscriber + ` +- :php:`MongoDB\Driver\Monitoring\CommandSubscriber + ` From 8c2fae0e737ad6e3fd0a2a0b23b912b9fa9a1524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 22 Nov 2023 16:25:40 +0100 Subject: [PATCH 3/4] Doc review Co-authored-by: Jeremy Mikola --- .../apiargs-MongoDBClient-method-addSubscriber-param.yaml | 2 +- ...iargs-MongoDBClient-method-removeSubscriber-param.yaml | 4 ++-- docs/reference/method/MongoDBClient-addSubscriber.txt | 8 +++++--- docs/reference/method/MongoDBClient-removeSubscriber.txt | 4 +++- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml b/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml index 22c9fb09c..27de61506 100644 --- a/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-addSubscriber-param.yaml @@ -1,6 +1,6 @@ arg_name: param name: $subscriber -type: MongoDB\Driver\Monitoring\Subscriber +type: :php:`MongoDB\\Driver\\Monitoring\\Subscriber ` description: | A monitoring event subscriber to register with this Client. interface: phpmethod diff --git a/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml b/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml index 22c9fb09c..eaeec4fdf 100644 --- a/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-removeSubscriber-param.yaml @@ -1,8 +1,8 @@ arg_name: param name: $subscriber -type: MongoDB\Driver\Monitoring\Subscriber +type: :php:`MongoDB\\Driver\\Monitoring\\Subscriber ` description: | - A monitoring event subscriber to register with this Client. + A monitoring event subscriber to unregister with this Client. interface: phpmethod operation: ~ optional: false diff --git a/docs/reference/method/MongoDBClient-addSubscriber.txt b/docs/reference/method/MongoDBClient-addSubscriber.txt index 9102b852f..ffc30f795 100644 --- a/docs/reference/method/MongoDBClient-addSubscriber.txt +++ b/docs/reference/method/MongoDBClient-addSubscriber.txt @@ -2,6 +2,8 @@ MongoDB\\Client::addSubscriber() ================================ +.. versionadded:: 1.18 + .. default-domain:: mongodb .. contents:: On this page @@ -28,8 +30,8 @@ Definition .. note:: - If $subscriber is already registered with this Client, this function - is a no-op. If $subscriber is also registered globally, it will still + 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 @@ -109,7 +111,7 @@ The subscriber can then be registered with a Client: $client->test->users->insertOne(['username' => 'alice']); -The above code will log the following to err output: +The above code will write the following to stderr output: .. code-block:: text diff --git a/docs/reference/method/MongoDBClient-removeSubscriber.txt b/docs/reference/method/MongoDBClient-removeSubscriber.txt index 2b2249b87..cfb1c2490 100644 --- a/docs/reference/method/MongoDBClient-removeSubscriber.txt +++ b/docs/reference/method/MongoDBClient-removeSubscriber.txt @@ -2,6 +2,8 @@ MongoDB\\Client::removeSubscriber() ================================ +.. versionadded:: 1.18 + .. default-domain:: mongodb .. contents:: On this page @@ -27,7 +29,7 @@ Definition .. note:: - If $subscriber is not registered with this Client, this function + If ``$subscriber`` is not registered with this Client, this function is a no-op. Errors/Exceptions From 0888ba743cc6c95ac22f3d5a0e17e84f5504d12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 22 Nov 2023 16:55:19 +0100 Subject: [PATCH 4/4] Doc review + update example to use the Client method --- .../method/MongoDBClient-addSubscriber.txt | 116 +++++++++--------- .../method/MongoDBClient-removeSubscriber.txt | 11 +- examples/command_logger.php | 2 +- 3 files changed, 62 insertions(+), 67 deletions(-) diff --git a/docs/reference/method/MongoDBClient-addSubscriber.txt b/docs/reference/method/MongoDBClient-addSubscriber.txt index ffc30f795..e55a94841 100644 --- a/docs/reference/method/MongoDBClient-addSubscriber.txt +++ b/docs/reference/method/MongoDBClient-addSubscriber.txt @@ -39,6 +39,11 @@ 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 ------- @@ -49,54 +54,54 @@ logs all events: 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, + )); + } - class LogCommandSubscriber implements CommandSubscriber + public function commandFailed(CommandFailedEvent $event): void { - private $stream; - public function __construct($stream) - { - $this->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, - )); - } + 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: @@ -104,29 +109,24 @@ The subscriber can then be registered with a Client: addSubscriber($subscriber); + $client->addSubscriber($subscriber); - $client->test->users->insertOne(['username' => 'alice']); + $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 3349 microseconds: {"n":1,"ok":1} + 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\Subscriber - ` -- :php:`MongoDB\Driver\Monitoring\CommandSubscriber - ` +- :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 index cfb1c2490..28e7e6d96 100644 --- a/docs/reference/method/MongoDBClient-removeSubscriber.txt +++ b/docs/reference/method/MongoDBClient-removeSubscriber.txt @@ -41,11 +41,6 @@ See Also -------- - :phpmethod:`MongoDB\\Client::addSubscriber()` -- :php:`Application Performance Monitoring (APM) - ` -- :php:`MongoDB\\Driver\\Manager::removeSubscriber() - ` -- :php:`MongoDB\Driver\Monitoring\Subscriber - ` -- :php:`MongoDB\Driver\Monitoring\CommandSubscriber - ` +- :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();