Monitor Application Events (original) (raw)

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

Monitoring involves collecting information about the activities of a running program, which you can use with an application performance management library.

Monitoring the Node.js 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:

This guide shows how to use information about the activity of the driver in code. To learn how to record events in the driver, see the Node.js driver'sLogging guide.

You can monitor events using the Node.js driver by subscribing to them in your application.

An event is any action that occurs within the driver during its operation. The Node.js driver includes functionality for listening to a subset of these events.

The Node.js driver organizes the events it defines into the following categories:

The following sections show how to monitor each event category.

A command event is an event related to a MongoDB database command. You can access one or more command monitoring events using the driver by subscribing to them in your application.

To learn more about MongoDB database commands, see theDatabase Commands guide in the Server Manual.

Note

Command monitoring is disabled by default. To enable command monitoring, pass the monitorCommands option as true to your MongoClient constructor.

The following example demonstrates connecting to a replica set and subscribing to one of the command monitoring events created by the MongoDB deployment:


/* Subscribe to an event */

const { MongoClient } = require("mongodb");

// Replace the following with your MongoDB deployment's connection string

const uri = "mongodb+srv://<clusterUrl>/?replicaSet=rs&writeConcern=majority";

const client = new MongoClient(uri, { monitorCommands:true });

// Replace <event name> with the name of the event you are subscribing to

const eventName = "<event name>";

// Subscribes to a specified event and print a message when the event is received

client.on(eventName, event => console.log(event));

async function run() {

  try {

    // Establishes and verifies connection to the "admin" database

    await client.db("admin").command({ ping: 1 });

    console.log("Connected successfully");

  } finally {

    // Closes the database connection on completion or error

    await client.close();

  }

}

run().catch(console.dir);

You can subscribe to any of the following command monitoring events:

Event Name Description
commandStarted Created when a command is started.
commandSucceeded Created when a command succeeded.
commandFailed Created when a command failed.

CommandStartedEvent {

  requestId: 1534,

  databaseName: "app",

  commandName: "find",

  address: 'localhost:27017',

  connectionId: 812613,

  command: {

    find: { firstName: "Jane", lastName: "Doe" }

  }

}


CommandSucceededEvent {

  requestId: 1534,

  commandName: "find",

  address: 'localhost:27017',

  connectionId: 812613,

  duration: 15,

  reply: {

    cursor: {

      firstBatch: [

        {

          _id: ObjectId("5e8e2ca217b5324fa9847435"),

          firstName: "Jane",

          lastName: "Doe"

        }

      ],

      _id: 0,

      ns: "app.users"

    },

    ok: 1,

    operationTime: 1586380205

  }

}


CommandFailedEvent {

  requestId: 1534,

  commandName: "find",

  address: 'localhost:27017',

  connectionId: 812613,

  failure: Error("something failed"),

  duration: 11

}

The Node.js driver creates topology events, also known as SDAM events, when there is a change in the state of the instance or cluster that you connected to. For example, the driver creates an event when you establish a new connection or if the cluster elects a new primary node.

To learn more about topology events, see the Replication guide in the Server Manual.

The following sections demonstrate how to record topology changes in your application and explore the information provided in these events.

You can access one or more SDAM events by subscribing to them in your application. The following example demonstrates connecting to a replica set and subscribing to one of the SDAM events created by the MongoDB deployment:


/* Subscribe to SDAM event */

const { MongoClient } = require("mongodb");

// Replace the following with your MongoDB deployment's connection string

const uri = "mongodb+srv://<clusterUrl>/?replicaSet=rs&writeConcern=majority";

const client = new MongoClient(uri);

// Replace <event name> with the name of the event you are subscribing to

const eventName = "<event name>";

// Subscribes to a specified event and prints a message when the event is received

client.on(eventName, event => {

  console.log(`received <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>e</mi><mi>v</mi><mi>e</mi><mi>n</mi><mi>t</mi><mi>N</mi><mi>a</mi><mi>m</mi><mi>e</mi></mrow><mo>:</mo></mrow><annotation encoding="application/x-tex">{eventName}: </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6833em;"></span><span class="mord"><span class="mord mathnormal">e</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mord mathnormal">e</span><span class="mord mathnormal">n</span><span class="mord mathnormal" style="margin-right:0.10903em;">tN</span><span class="mord mathnormal">am</span><span class="mord mathnormal">e</span></span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span></span></span></span>{JSON.stringify(event, null, 2)}`);

});

async function run() {

  try {

    // Establishes and verifies connection to the database

    await client.db("admin").command({ ping: 1 });

    console.log("Connected successfully");

  } finally {

    // Closes the database connection on completion or error

    await client.close();

  }

}

run().catch(console.dir);

You can subscribe to any of the following SDAM events:

Event Name Description
serverOpening Created when a connection to an instance opens.
serverClosed Created when a connection to an instance closes.
serverDescriptionChanged Created when an instance state changes (such as from secondary to primary).
topologyOpening Created before attempting a connection to an instance.
topologyClosed Created after all instance connections in the topology close.
topologyDescriptionChanged Created when the topology changes, such as an election of a new primary or a mongos proxy disconnecting.
serverHeartbeatStarted Created before issuing a hello command to a MongoDB instance.
serverHeartbeatSucceeded Created when the hello command returns successfully from a MongoDB instance.
serverHeartbeatFailed Created when a hello command issued to a specific MongoDB instance fails to return a successful response.

The following sections show sample output for each type of SDAM event.


ServerDescriptionChangedEvent {

  topologyId: 0,

  address: 'localhost:27017',

  previousDescription: ServerDescription {

    address: 'localhost:27017',

    error: null,

    roundTripTime: 0,

    lastUpdateTime: 1571251089030,

    lastWriteDate: null,

    opTime: null,

    type: 'Unknown',

    minWireVersion: 0,

    maxWireVersion: 0,

    hosts: [],

    passives: [],

    arbiters: [],

    tags: []

  },

  newDescription: ServerDescription {

    address: 'localhost:27017',

    error: null,

    roundTripTime: 0,

    lastUpdateTime: 1571251089051,

    lastWriteDate: 2019-10-16T18:38:07.000Z,

    opTime: { ts: Timestamp, t: 18 },

    type: 'RSPrimary',

    minWireVersion: 0,

    maxWireVersion: 7,

    maxBsonObjectSize: 16777216,

    maxMessageSizeBytes: 48000000,

    maxWriteBatchSize: 100000,

    me: 'localhost:27017',

    hosts: [ 'localhost:27017' ],

    passives: [],

    arbiters: [],

    tags: [],

    setName: 'rs',

    setVersion: 1,

    electionId: ObjectID,

    primary: 'localhost:27017',

    logicalSessionTimeoutMinutes: 30,

    '$clusterTime': ClusterTime

  }

}

The type field of the ServerDescription object in this event contains one of the following possible values:

Type Description
Unknown Unknown instance
Standalone Standalone instance
Mongos Mongos proxy instance
PossiblePrimary At least one server recognizes this as the primary, but is not yet verified by all instances.
RSPrimary Primary instance
RSSecondary Secondary instance
RSArbiter Arbiter instance
RSOther See the RSGhost and RSOther specificationfor more details
RSGhost See the RSGhost and RSOther specificationfor more details

ServerHeartbeatStartedEvent {

  connectionId: 'localhost:27017'

}


ServerHeartbeatSucceededEvent {

  duration: 1.939997,

  reply:{

    hosts: [ 'localhost:27017' ],

    setName: 'rs',

    setVersion: 1,

    isWritablePrimary: true,

    secondary: false,

    primary: 'localhost:27017',

    me: 'localhost:27017',

    electionId: ObjectID,

    lastWrite: {

      opTime: { ts: [Timestamp], t: 18 },

      lastWriteDate: 2019-10-16T18:38:17.000Z,

      majorityOpTime: { ts: [Timestamp], t: 18 },

      majorityWriteDate: 2019-10-16T18:38:17.000Z

    },

    maxBsonObjectSize: 16777216,

    maxMessageSizeBytes: 48000000,

    maxWriteBatchSize: 100000,

    localTime: 2019-10-16T18:38:19.589Z,

    logicalSessionTimeoutMinutes: 30,

    minWireVersion: 0,

    maxWireVersion: 7,

    readOnly: false,

    ok: 1,

    operationTime: Timestamp,

    '$clusterTime': ClusterTime

  },

  connectionId: 'localhost:27017'

}


ServerHeartbeatFailed {

  duration: 20,

  failure: MongoError('some error'),

  connectionId: 'localhost:27017'

}


ServerOpeningEvent {

  topologyId: 0,

  address: 'localhost:27017'

}


ServerClosedEvent {

  topologyId: 0,

  address: 'localhost:27017'

}


TopologyOpeningEvent {

  topologyId: 0

}


TopologyClosedEvent {

  topologyId: 0

}


TopologyDescriptionChangedEvent {

  topologyId: 0,

  previousDescription: TopologyDescription {

    type: 'ReplicaSetNoPrimary',

    setName: null,

    maxSetVersion: null,

    maxElectionId: null,

    servers: Map {

      'localhost:27017' => ServerDescription

    },

    stale: false,

    compatible: true,

    compatibilityError: null,

    logicalSessionTimeoutMinutes: null,

    heartbeatFrequencyMS: 10000,

    localThresholdMS: 15,

    options: Object,

    error: undefined,

    commonWireVersion: null

  },

  newDescription: TopologyDescription {

    type: 'ReplicaSetWithPrimary',

    setName: 'rs',

    maxSetVersion: 1,

    maxElectionId: null,

    servers: Map {

      'localhost:27017' => ServerDescription

    },

    stale: false,

    compatible: true,

    compatibilityError: null,

    logicalSessionTimeoutMinutes: 30,

    heartbeatFrequencyMS: 10000,

    localThresholdMS: 15,

    options: Object,

    error: undefined,

    commonWireVersion: 7

  }

}

The type field of the TopologyDescription object in this event contains one of the following possible values:

Type Description
Single Standalone instance
ReplicaSetWithPrimary Replica set with a primary
ReplicaSetNoPrimary Replica set with no primary
Sharded Sharded cluster
Unknown Unknown topology

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 and can help your application run faster.

The following sections demonstrate how to record connection pool events in your application and explore the information provided in these events.

You can access one or more connection pool events using the driver by subscribing to them in your application. The following example demonstrates connecting to a replica set and subscribing to one of the connection pool monitoring events created by the MongoDB deployment:


const { MongoClient } = require("mongodb");

// Replace the following with your MongoDB deployment's connection string

const uri =

  "mongodb+srv://<clusterUrl>/?replicaSet=rs&writeConcern=majority";

const client = new MongoClient(uri);

// Replace <event name> with the name of the event you are subscribing to

const eventName = "<event name>";

// Subscribes to the event

client.on(eventName, (event) =>

  console.log("\nreceived event:\n", event)

);

async function run() {

  try {

    // Establishes and verifies connection

    await client.db("admin").command({ ping: 1 });

    console.log("\nConnected successfully!\n");

  } finally {

    // Ensures that the client will close when you finish/error

    await client.close();

  }

}

run().catch(console.dir);

Connection pool monitoring events can aid you in debugging and understanding the behavior of your application's connection pool. The following example uses connection pool monitoring events to return a count of checked-out connections in the pool:


function connectionPoolStatus(client) {

  let checkedOut = 0;

  function onCheckout() {

    checkedOut++;

  }

  function onCheckin() {

    checkedOut--;

  }

  function onClose() {

    client.removeListener('connectionCheckedOut', onCheckout);

    client.removeListener('connectionCheckedIn', onCheckin);

    checkedOut = NaN;

  }

  // Decreases count of connections checked out of the pool when connectionCheckedIn event is triggered

  client.on('connectionCheckedIn', onCheckin);

  // Increases count of connections checked out of the pool when connectionCheckedOut event is triggered

  client.on('connectionCheckedOut', onCheckout);

  // Cleans up event listeners when client is closed

  client.on('close', onClose);

  return {

    count: () => checkedOut,

    cleanUp: onClose

  };

}

You can subscribe to any of the following connection pool monitoring events:

Event Name Description
connectionPoolCreated Created when a connection pool is created.
connectionPoolReady Created when a connection pool is ready.
connectionPoolClosed Created when a connection pool is closed before server instance destruction.
connectionCreated Created when a connection is created, but not necessarily when it is used for an operation.
connectionReady Created after a connection has successfully completed a handshake and is ready to be used for operations.
connectionClosed Created when a connection is closed.
connectionCheckOutStarted Created when an operation attempts to acquire a connection for execution.
connectionCheckOutFailed Created when an operation fails to acquire a connection for execution.
connectionCheckedOut Created when an operation successfully acquires a connection for execution.
connectionCheckedIn Created when a connection is checked back into the pool after an operation is executed.
connectionPoolCleared Created when all connections are closed and the connection pool is cleared.

The following sections show sample output for each type of connection pool monitoring event.


ConnectionPoolCreatedEvent {

  time: 2023-02-13T15:54:06.944Z,

  address: '...',

  options: {...}

}


ConnectionPoolReadyEvent {

  time: 2023-02-13T15:56:38.440Z,

  address: '...'

}


ConnectionPoolClosedEvent {

  time: 2023-02-13T15:56:38.440Z,

  address: '...'

}


ConnectionCreatedEvent {

  time: 2023-02-13T15:56:38.291Z,

  address: '...',

  connectionId: 1

}


ConnectionReadyEvent {

  time: 2023-02-13T15:56:38.291Z,

  address: '...',

  connectionId: 1,

  durationMS: 60

}


ConnectionClosedEvent {

  time: 2023-02-13T15:56:38.439Z,

  address: '...',

  connectionId: 1,

  reason: 'poolClosed',

  serviceId: undefined

}


ConnectionCheckOutStartedEvent {

  time: 2023-02-13T15:56:38.291Z,

  address: '...',

}


ConnectionCheckOutFailedEvent {

  time: 2023-02-13T15:56:38.291Z,

  address: '...',

  reason: ...,

  durationMS: 60

}


ConnectionCheckedOutEvent {

  time: 2023-02-13T15:54:07.188Z,

  address: '...',

  connectionId: 1,

  durationMS: 60

}


ConnectionCheckedInEvent {

  time: 2023-02-13T15:54:07.189Z,

  address: '...',

  connectionId: 1

}


ConnectionPoolClearedEvent {

  time: 2023-02-13T15:56:38.439Z,

  address: '...',

  serviceId: undefined,

  interruptInUseConnections: true,

}

To learn more about any of the options or types discussed in this guide, see the following API documentation: