diff --git a/source/includes/monitoring_JMX.kt b/source/includes/monitoring_JMX.kt new file mode 100644 index 00000000..d3c3877f --- /dev/null +++ b/source/includes/monitoring_JMX.kt @@ -0,0 +1,36 @@ +import com.mongodb.kotlin.client.MongoClient +import org.bson.Document +import com.mongodb.MongoClientSettings +import com.mongodb.ConnectionString +import com.mongodb.management.JMXConnectionPoolListener + +fun main() { + val uri = "" + +// Instantiate your JMX listener + val connectionPoolListener = JMXConnectionPoolListener() + +// Include the listener in your client settings + val settings = MongoClientSettings.builder() + .applyConnectionString(ConnectionString(uri)) + .applyToConnectionPoolSettings { + it.addConnectionPoolListener(connectionPoolListener) + } + .build() + + try { +// Connect to your database + val mongoClient = MongoClient.create(settings) + val database = mongoClient.getDatabase("sample_mflix") + val collection = database.getCollection("movies") + collection.find().firstOrNull() + collection.find().firstOrNull() + println("Navigate to JConsole to see your connection pools...") + +// Pause execution + Thread.sleep(Long.MAX_VALUE) + mongoClient.close() + } catch (e: Exception) { + e.printStackTrace() + } +} \ No newline at end of file diff --git a/source/includes/monitoring_counter.kt b/source/includes/monitoring_counter.kt new file mode 100644 index 00000000..254b7cdc --- /dev/null +++ b/source/includes/monitoring_counter.kt @@ -0,0 +1,45 @@ +import com.mongodb.kotlin.client.MongoClient +import org.bson.Document +import com.mongodb.event.* +import com.mongodb.MongoClientSettings +import com.mongodb.ConnectionString + +class CommandCounter : CommandListener { + private val commands = mutableMapOf() + + override fun commandSucceeded(event: CommandSucceededEvent) { + val commandName = event.commandName + val count = commands[commandName] ?: 0 + commands[commandName] = count + 1 + println(commands.toString()) + } + + override fun commandFailed(event: CommandFailedEvent) { + println("Failed execution of command '${event.commandName}' with id ${event.requestId}") + } +} + + +fun main() { + val uri = "" + +// Instantiate your new listener + val commandCounter = CommandCounter() + +// Include the listener in your client settings + val settings = MongoClientSettings.builder() + .applyConnectionString(ConnectionString(uri)) + .addCommandListener(commandCounter) + .build() + +// Connect to your database + val mongoClient = MongoClient.create(settings) + val database = mongoClient.getDatabase("sample_mflix") + val collection = database.getCollection("movies") + +// Run some commands to test the counter + collection.find().firstOrNull() + collection.find().firstOrNull() + + mongoClient.close() +} \ No newline at end of file diff --git a/source/includes/monitoring_librarian.kt b/source/includes/monitoring_librarian.kt new file mode 100644 index 00000000..dd2abed2 --- /dev/null +++ b/source/includes/monitoring_librarian.kt @@ -0,0 +1,40 @@ +import com.mongodb.kotlin.client.MongoClient +import org.bson.Document +import com.mongodb.event.* +import com.mongodb.MongoClientSettings +import com.mongodb.ConnectionString + +class ConnectionPoolLibrarian : ConnectionPoolListener { + override fun connectionCheckedOut(event: ConnectionCheckedOutEvent) { + println("Let me get you the connection with id ${event.connectionId.localValue}...") + } + override fun connectionCheckOutFailed(event: ConnectionCheckOutFailedEvent) { + println("Something went wrong! Failed to checkout connection.") + } +} + + +fun main() { + val uri = "" + +// Instantiate your new listener +val cpListener = ConnectionPoolLibrarian() + +// Include the listener in your client settings + val settings = MongoClientSettings.builder() + .applyConnectionString(ConnectionString(uri)) + .applyToConnectionPoolSettings({ + it.addConnectionPoolListener(cpListener) + }) + .build() + +// Connect to your database + val mongoClient = MongoClient.create(settings) + val database = mongoClient.getDatabase("sample_mflix") + val collection = database.getCollection("movies") + +// Run some commands to test the counter + collection.find().firstOrNull() + + mongoClient.close() +} \ No newline at end of file diff --git a/source/includes/monitoring_writable.kt b/source/includes/monitoring_writable.kt new file mode 100644 index 00000000..6d81036f --- /dev/null +++ b/source/includes/monitoring_writable.kt @@ -0,0 +1,49 @@ +import com.mongodb.kotlin.client.MongoClient +import org.bson.Document +import com.mongodb.event.* +import com.mongodb.MongoClientSettings +import com.mongodb.ConnectionString + +class IsWriteable : ClusterListener { + private var isWritable = false + + override fun clusterDescriptionChanged(event: ClusterDescriptionChangedEvent) { + if (!isWritable) { + if (event.newDescription.hasWritableServer()) { + isWritable = true + println("Able to write to cluster") + } + } else { + if (!event.newDescription.hasWritableServer()) { + isWritable = false + println("Unable to write to cluster") + } + } + } +} + + +fun main() { + val uri = "" + +// Instantiate your new listener + val clusterListener = IsWriteable() + +// Include the listener in your client settings + val settings = MongoClientSettings.builder() + .applyConnectionString(ConnectionString(uri)) + .applyToClusterSettings { builder -> + builder.addClusterListener(clusterListener) + } + .build() + +// Connect to your database + val mongoClient = MongoClient.create(settings) + val database = mongoClient.getDatabase("sample_mflix") + val collection = database.getCollection("movies") + +// Run a command to trigger a ClusterDescriptionChangedEvent event + collection.find().firstOrNull() + + mongoClient.close() +} \ No newline at end of file diff --git a/source/index.txt b/source/index.txt index 902854c6..4534ed0f 100644 --- a/source/index.txt +++ b/source/index.txt @@ -23,6 +23,7 @@ Specialized Data Formats Builders Run a Command + Monitoring Security In-Use Encryption Compatibility diff --git a/source/monitoring.txt b/source/monitoring.txt new file mode 100644 index 00000000..403f3e0a --- /dev/null +++ b/source/monitoring.txt @@ -0,0 +1,391 @@ +========== +Monitoring +========== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Overview +-------- + +In this guide, you can learn how to set up and configure **monitoring** in the +{+driver-short+}. + +Monitoring is the process of getting information about the activities a running +program performs for use in an application or an application performance +management library. + +You can use the {+driver-short+} to monitor cluster, driver command, and +connection pool events. These features help you make informed decisions when +designing and debugging your application. + +This guide shows how to perform the following tasks: + +- :ref:`Monitor specific events by using the {+driver-short+} ` +- :ref:`Monitor connection pool events with Java Management Extensions (JMX) and JConsole ` + +.. tip:: + + This guide shows how to use information about the meta activity of the driver. + To learn how to record data transactions, see the :ref:`Monitoring Data Changes ` page. + +.. _monitoring-monitor-events: + +Monitor Events +-------------- + +To monitor an **event**, you must register a **listener** on your ``MongoClient`` +instance. + +An event is any action that happens in a running program. The driver includes functionality +for listening to a subset of the events that occur when the driver is running. + +A listener is a class that performs some action when certain events occur. +A listener's API defines the events it can respond to. + +Each method of a listener class represents a response to a certain event, and +accepts as an argument an event object representing the event. + +The {+driver-short+} organizes the events it defines into three categories: + +- Command events +- Server Discovery and Monitoring events +- Connection Pool events + +The following sections show how to monitor each event category. For a full list of the events you can monitor, +`see the Java event package +<{+core-api+}/com/mongodb/event/package-summary.html>`__. + +.. _command-events-kotlin: + +Command Events +~~~~~~~~~~~~~~ + +A command event is an event related to a MongoDB database command. Some +examples of database commands that produce command events are ``find``, +``insert``, ``delete``, and ``count``. + +To monitor command events, create a class that implements the +``CommandListener`` interface and register an instance of that class with your +``MongoClient`` instance. + +For more information on MongoDB database commands, see the +:manual:`MongoDB manual entry on database commands `in +the {+mdb-server+} manual. + +.. note:: Internal Commands + + The driver does not publish events for commands it calls internally. This + includes database commands the driver uses to monitor your cluster and + commands related to connection establishment, such as the initial ``hello`` + command. + +.. important:: Redacted Output + + As a security measure, the driver redacts the contents of some command events. This + protects the sensitive information contained in these command events. For a + full list of redacted command events, see the + :spec:`MongoDB command logging and monitoring specification `. + +Example +^^^^^^^ + +This example shows how to make a counter for database commands. The counter +keeps track of the number of times the driver successfully executes each database +command and prints this information every time a database command finishes. + +To make a counter, follow these steps: + +#. Make a class with counter functionality that implements the ``CommandListener`` interface. +#. Add an instance of the new class to a ``MongoClientSettings`` object. +#. Configure your ``MongoClient`` instance with the ``MongoClientSettings`` object. + +The following code implements these steps: + +.. _listener-mongo-client-settings-example: + +.. io-code-block:: + + .. input:: /includes/monitoring_counter.kt + :language: kotlin + + .. output:: + :language: console + :visible: false + + {find=1} + {find=2} + {find=2, endSessions=1} + +For more information on the classes and methods mentioned in this section, see +the following API documentation: + +- `CommandListener <{+core-api+}/com/mongodb/event/CommandListener.html>`__ +- `MongoClientSettings <{+core-api+}/com/mongodb/MongoClientSettings.html>`__ +- `MongoClient <{+api+}/com.mongodb.kotlin.client/-mongo-client/index.html>`__ +- `CommandStartedEvent <{+core-api+}/com/mongodb/event/CommandStartedEvent.html>`__ +- `CommandSucceededEvent <{+core-api+}/com/mongodb/event/CommandSucceededEvent.html>`__ +- `CommandFailedEvent <{+core-api+}/com/mongodb/event/CommandFailedEvent.html>`__ + +Server Discovery and Monitoring Events +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A server discovery and monitoring (SDAM) event is an event related to a change +in the state of the MongoDB instance or cluster you have connected the driver to. + +The driver defines nine SDAM events and provides the following listener +interfaces, which listen for three SDAM events each: + +- `ClusterListener <{+core-api+}/com/mongodb/event/ClusterListener.html>`__ : Listens for topology-related events +- `ServerListener <{+core-api+}/com/mongodb/event/ServerListener.html>`__ : Listens for events related to ``mongod`` or ``mongos`` processes +- `ServerMonitorListener <{+core-api+}/com/mongodb/event/ServerMonitorListener.html>`__ : Listens for heartbeat-related events + +To monitor a type of SDAM event, create a class that implements one of the three +preceding interfaces and register an instance of that class with your +``MongoClient`` instance. + +For a detailed description of each SDAM event, see the :spec:`MongoDB SDAM monitoring events specification `. + +Example +^^^^^^^ + +This example shows how to make a listener class that prints a message about the write +availability of your MongoDB instance. + +To make an event that reports write status, perform the following tasks: + +#. Make a class that tracks cluster description changes, and + implements the ``ClusterListener`` interface. +#. Add an instance of the new class to a ``MongoClientSettings`` object. +#. Configure your ``MongoClient`` instance with the ``MongoClientSettings`` object. + +The following code implements these steps: + +.. io-code-block:: + + .. input:: /includes/monitoring_writable.kt + :language: kotlin + + .. output:: + :language: console + :visible: false + + Able to write to server + +For more information on the classes and methods mentioned in this section, see +the following API documentation: + +- `ClusterListener <{+core-api+}/com/mongodb/event/ClusterListener.html>`__ +- `ServerListener <{+core-api+}/com/mongodb/event/ServerListener.html>`__ +- `ServerMonitorListener <{+core-api+}/com/mongodb/event/ServerMonitorListener.html>`__ +- `MongoClientSettings <{+core-api+}/com/mongodb/MongoClientSettings.html>`__ +- `MongoClient <{+api+}/com.mongodb.kotlin.client/-mongo-client/index.html>`__ +- `ClusterDescriptionChangedEvent <{+core-api+}/com/mongodb/event/ClusterDescriptionChangedEvent.html>`__ + +Connection Pool Events +~~~~~~~~~~~~~~~~~~~~~~ + +A connection pool event is an event related to a **connection pool** held by the driver. +A connection pool is a set of open TCP connections your driver maintains with +a MongoDB instance. Connection pools help reduce the number of network handshakes +your application performs with a MongoDB instance and can help your +application run faster. + +To monitor connection pool events, create a class that implements the +``ConnectionPoolListener`` interface and register an instance of that class with your +``MongoClient`` instance. + +Example +^^^^^^^ + +This example shows how to make a listener class that prints a message each time +you check out a connection from your connection pool. + +To make an event that reports connection checkouts, perform the following tasks: + +#. Make a class that tracks checkouts and implements the ``CommandListener`` interface. +#. Add an instance of the new class to a ``MongoClientSettings`` object. +#. Configure your ``MongoClient`` instance with the ``MongoClientSettings`` object. + +The following code implements these steps: + +.. io-code-block:: + + .. input:: /includes/monitoring_librarian.kt + :language: kotlin + + .. output:: + :language: console + :visible: false + + Let me get you the connection with id 21... + +For more information on the classes and methods mentioned in this section, see +the following API documentation: + +- `ConnectionPoolListener <{+core-api+}/com/mongodb/event/ConnectionPoolListener.html>`__ +- `MongoClientSettings <{+core-api+}/com/mongodb/MongoClientSettings.html>`__ +- `MongoClient <{+api+}/com.mongodb.kotlin.client/-mongo-client/index.html>`__ +- `ConnectionCheckedOutEvent <{+core-api+}/com/mongodb/event/ConnectionCheckedOutEvent.html>`__ +- `ConnectionCheckOutFailedEvent <{+core-api+}/com/mongodb/event/ConnectionCheckOutFailedEvent.html>`__ + +.. _monitoring-jmx: + +Monitor Connection Pool Events with JMX +--------------------------------------- + +You can monitor connection pool events using **Java Management Extensions (JMX)**. +JMX provides tools to monitor applications and devices. + +For more information on JMX, see +`the official Oracle JMX documentation `__. + +JMX Support +~~~~~~~~~~~ + +To enable JMX connection pool monitoring, add an instance of the +``JMXConnectionPoolListener`` class to your ``MongoClient`` object. + +The ``JMXConnectionPoolListener`` class performs the following actions: + +#. Creates MXBean instances for each ``mongod`` or ``mongos`` process the driver + maintains a connection pool with. +#. Registers these MXBean instances with the platform MBean server. + +MXBeans registered on the platform MBean server have the following properties: + +.. list-table:: + :header-rows: 1 + :widths: 10 20 + + * - Property + - Description + + * - ``clusterId`` + - A client-generated unique identifier. This identifier ensures that + each MXBean the driver makes has a unique name when an application has + multiple ``MongoClient`` instances connected to the same MongoDB deployment. + + * - ``host`` + - The hostname of the machine running the ``mongod`` or ``mongos`` process. + + * - ``port`` + - The port on which the ``mongod`` or ``mongos`` process is listening. + + * - ``minSize`` + - The minimum size of the connection pool, including idle and in-use connections. + + * - ``maxSize`` + - The maximum size of the connection pool, including idle and in-use connections. + + * - ``size`` + - The current size of the connection pool, including idle and in-use connections. + + * - ``checkedOutCount`` + - The current count of connections that are in use. + + +All MXBean instances created by the driver are under the domain +``"org.mongodb.driver"``. + +For more information on the topics discussed in this subsection, see the +following resources from Oracle: + +- `Platform MBean Server Reference Documentation `__ +- `MXBean Documentation `__ +- `MBean Documentation `__ + +JMX and JConsole Example +~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how you can monitor the driver's connection pools using JMX +and **JConsole**. JConsole is a JMX compliant GUI monitoring tool that comes with +the Java Platform. + +.. tip:: Consult the Official JMX and JConsole Documentation + + The descriptions of JMX and JConsole in this example are illustrative + rather than a source of truth. For guaranteed up-to-date information, consult + the following official Oracle resources: + + - `JConsole documentation `__ + - `JMX documentation `__ + +The following code snippet adds a ``JMXConnectionPoolListener`` to a +``MongoClient`` instance. The code then pauses execution so you can +navigate to JConsole and inspect your connection pools. + +.. io-code-block:: + + .. input:: /includes/monitoring_JMX.kt + :language: kotlin + + .. output:: + :language: console + :visible: false + + Navigate to JConsole to see your connection pools... + +Once you have started your server, open JConsole in your terminal by using the +following command: + +.. code-block:: shell + + jconsole + +Once JConsole is open, perform the following actions in the GUI: + +#. Select the process running the preceding example code. +#. Press :guilabel:`Insecure Connection` in the warning dialog box. +#. Click on the :guilabel:`MBeans` tab. +#. Inspect your connection pool events under the ``"org.mongodb.driver"`` domain. + +When you no longer want to inspect your connection pools in JConsole, do the +following: + +#. Exit JConsole by closing the JConsole window. +#. Stop the program running by the preceding code snippet. + +For more information on JMX and JConsole, see the following resources from +Oracle: + +- `JConsole Documentation `__ +- `Monitoring and Management Guide `__ + +For more information on the ``JMXConnectionPoolListener`` class, see +the API documentation for +`JMXConnectionPoolListener <{+core-api+}/com/mongodb/management/JMXConnectionPoolListener.html>`__. + +Include the Driver in Your Distributed Tracing System +----------------------------------------------------- + +If you use a **distributed tracing system**, you can include event data from the +driver. A distributed tracing system is an application that +tracks requests as they propagate throughout different services in a +service-oriented architecture. + +If you use the driver in a `Spring Cloud `__ +application, use Spring Cloud Sleuth to include MongoDB event data in the +`Zipkin `__ distributed tracing system. + +If you do not use Spring Cloud or want to include driver event data in a distributed +tracing system other than Zipkin, you must write a command event listener that +manages **spans** for your desired distributed tracing system. + +.. tip:: + + To learn more about the concepts discussed in this section, review the + following resources: + + - `Spring Cloud `__ + - `Spring Cloud Sleuth `__ + - `spans `__ + - :github:`TraceMongoCommandListener ` + : An implementation of an event listen than manages spans + - `Getting Started `__ + - `Zipkin `__ + - `Dapper `__ : A detailed + description of a distributed tracing system from Google Research