Docs Menu
Docs Home
/ / /
Kotlin Coroutine
/

Monitoring

On this page

  • Overview
  • Monitor Events
  • Command Events
  • Server Discovery and Monitoring Events
  • Connection Pool Events
  • Monitor Connection Pool Events with JMX
  • JMX Support
  • JMX and JConsole Example
  • Include the Driver in Your Distributed Tracing System

In this guide, you can learn how to set up and configure monitoring in the MongoDB Kotlin driver.

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.

Monitoring the MongoDB Kotlin driver lets you understand the driver's resource usage and performance, and can help you make informed decisions when designing and debugging your application.

In this guide you will learn how to perform these tasks:

  • Monitor different types of events in the MongoDB Kotlin driver

  • Monitor connection pool events with Java Management Extensions (JMX) and JConsole

This guide shows how to use information about the activity of the driver in code. If you would like to learn how to record events in the driver, consider reading our guide on logging.

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. Each method receives one argument: an object representing the event the method responds to.

The MongoDB Kotlin driver 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 event package of the MongoDB Kotlin driver.

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, write 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 MongoDB manual entry on database commands.

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 MongoDB command logging and monitoring specification.

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, do the following:

  1. Make a class with counter functionality that implements the CommandListener interface.

  2. Add an instance of the new class that implements CommandListener to a MongoClientSettings object.

  3. Configure a MongoClient instance with the MongoClientSettings object.

The following code defines the CommandCounter class which implements the CommandListener interface:

class CommandCounter : CommandListener {
private val commands = mutableMapOf<String, Int>()
@Synchronized
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}")
}
}

The following code adds an instance of the CommandCounter class to a MongoClientSettings object, and configures a MongoClient instance with the MongoClientSettings object. The code then runs some database commands to test the counter.

val commandCounter = CommandCounter()
val settings = MongoClientSettings.builder()
.applyConnectionString(URI)
.addCommandListener(commandCounter)
.build()
val mongoClient = MongoClient.create(settings)
val database = mongoClient.getDatabase(DATABASE)
val collection = database.getCollection<Document>(COLLECTION)
// Run some commands to test the counter
collection.find().firstOrNull()
collection.find().firstOrNull()
{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:

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. The driver divides these nine events between three separate listener interfaces which each listen for three of the nine events. Here are the three interfaces and the events they listen for:

  • ClusterListener: topology-related events

  • ServerListener: events related to mongod or mongos processes

  • ServerMonitorListener: heartbeat related events

To monitor a type of SDAM event, write 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 MongoDB SDAM monitoring events specification.

This example shows how to make a listener class that prints a message that lets you know if the driver can write to your MongoDB instance.

The following code defines the IsWritable class which implements the ClusterListener interface.

class IsWriteable : ClusterListener {
private var isWritable = false
@Synchronized
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")
}
}
}
}

The following code adds an instance of the IsWritable class to a MongoClient object. The code then runs a find operation to test the IsWritable class.

val clusterListener = IsWriteable()
val settings = MongoClientSettings.builder()
.applyConnectionString(URI)
.applyToClusterSettings { builder ->
builder.addClusterListener(clusterListener)
}
.build()
val mongoClient = MongoClient.create(settings)
val database = mongoClient.getDatabase(DATABASE)
val collection = database.getCollection<Document>(COLLECTION)
// Run a command to trigger a ClusterDescriptionChangedEvent event
collection.find().firstOrNull()
Able to write to server

For more information on the classes and methods mentioned in this section, see the following API Documentation:

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 needs to perform with a MongoDB instance, and can help your application run faster.

To monitor connection pool events, write a class that implements the ConnectionPoolListener interface and register an instance of that class with your MongoClient instance.

This example shows how to make a listener class that prints a message each time you check out a connection from your connection pool.

The following code defines the ConnectionPoolLibrarian class which implements the ConnectionPoolListener interface.

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.")
}
}

The following code adds an instance of the ConnectionPoolLibrarian class to a MongoClient object. The code then runs a database command to test the librarian.

val cpListener = ConnectionPoolLibrarian()
val settings = MongoClientSettings.builder()
.applyConnectionString(URI)
.applyToConnectionPoolSettings { builder ->
builder.addConnectionPoolListener(cpListener)
}
.build()
val mongoClient = MongoClient.create(settings)
val database = mongoClient.getDatabase(DATABASE)
val collection = database.getCollection<Document>(COLLECTION)
// Run a command to trigger connection pool events
collection.find().firstOrNull()
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:

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.

To enable JMX connection pool monitoring, add an instance of the JMXConnectionPoolListener class to your MongoClient object.

The JMXConnectionPoolListener class performs the following actions:

  1. Creates MXBean instances for each mongod or mongos process the driver maintains a connection pool with.

  2. Registers these MXBean instances with the platform MBean server.

MXBeans registered on the platform MBean server have the following properties:

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:

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:

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.

val connectionPoolListener = JMXConnectionPoolListener()
val settings = MongoClientSettings.builder()
.applyConnectionString(uri)
.applyToConnectionPoolSettings {
it.addConnectionPoolListener(connectionPoolListener)
}
.build()
val mongoClient: MongoClient = MongoClient.create(settings)
try {
println("Navigate to JConsole to see your connection pools...")
Thread.sleep(Long.MAX_VALUE)
} catch (e: Exception) {
e.printStackTrace()
}
Navigate to JConsole to see your connection pools...

Once you have started your server, open JConsole in your terminal using the following command:

jconsole

Once JConsole is open, perform the following actions in the GUI:

  1. Select the process running the preceding example code.

  2. Press Insecure Connection in the warning dialog box.

  3. Click on the MBeans tab.

  4. 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 the preceding code snippet

For more information on JMX and JConsole, see the following resources from Oracle:

For more information on the JMXConnectionPoolListener class, see the API Documentation for JMXConnectionPoolListener.

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 need 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. To see an implementation of such a listener, see the Java source code for the TraceMongoCommandListener class in the Spring Cloud Sleuth source code.

To learn more about Spring Cloud Sleuth, see Getting Started in the Spring Cloud Sleuth documentation.

To view a detailed description of a distributed tracing system, see Dapper from Google Research.

Back

Logging