mongoc_application_performance_monitoring man page

Introduction_to_Application_Performance_Monitoring_(APM) — None

Command-Monitoring Example

/* gcc example‐command‐monitoring.c ‐o example‐command‐monitoring \
 *     $(pkg‐config ‐‐cflags ‐‐libs libmongoc‐1.0) */

/* ./example‐command‐monitoring [CONNECTION_STRING] */

#include <mongoc.h>
#include <stdio.h>

typedef struct {
   int started;
   int succeeded;
   int failed;
} stats_t;

void
command_started (const mongoc_apm_command_started_t *event)
{
   char *s;
   
   s = bson_as_json (mongoc_apm_command_started_get_command (event), NULL);
   printf ("Command %s started on %s:\n%s\n\n",
           mongoc_apm_command_started_get_command_name (event),
           mongoc_apm_command_started_get_host (event)‐>host,
           s);
   
   ((stats_t *) mongoc_apm_command_started_get_context (event))‐>started++;
   
   bson_free (s);
}

void
command_succeeded (const mongoc_apm_command_succeeded_t *event)
{
   char *s;
   
   s = bson_as_json (mongoc_apm_command_succeeded_get_reply (event), NULL);
   printf ("Command %s succeeded:\n%s\n\n",
           mongoc_apm_command_succeeded_get_command_name (event),
           s);
   
   ((stats_t *) mongoc_apm_command_succeeded_get_context (event))‐>succeeded++;
   
   bson_free (s);
}

void
command_failed (const mongoc_apm_command_failed_t *event)
{
   bson_error_t error;
   
   mongoc_apm_command_failed_get_error (event, &error);
   printf ("Command %s failed:\n\"%s\"\n\n",
           mongoc_apm_command_failed_get_command_name (event),
           error.message);
   
   ((stats_t *) mongoc_apm_command_failed_get_context (event))‐>failed++;
}

int
main (int   argc,
      char *argv[])
{
   mongoc_client_t *client;
   mongoc_apm_callbacks_t *callbacks;
   stats_t stats = { 0 }; 
   mongoc_collection_t *collection;
   const char *uristr = "mongodb://127.0.0.1/?appname=cmd‐monitoring‐example";
   const char *collection_name = "test";
   bson_t doc;

   mongoc_init ();

   if (argc > 1) {
      uristr = argv [1];
   }

   client = mongoc_client_new (uristr);

   if (!client) {
      fprintf (stderr, "Failed to parse URI.\n");
      return EXIT_FAILURE;
   }

   mongoc_client_set_error_api (client, 2);
   callbacks = mongoc_apm_callbacks_new ();
   mongoc_apm_set_command_started_cb (callbacks, command_started);
   mongoc_apm_set_command_succeeded_cb (callbacks, command_succeeded );
   mongoc_apm_set_command_failed_cb (callbacks, command_failed);
   mongoc_client_set_apm_callbacks (client,
                                    callbacks,
                                    (void *) &stats /* context pointer */);

   bson_init (&doc);
   BSON_APPEND_INT32 (&doc, "_id", 1);

   collection = mongoc_client_get_collection (client, "test", collection_name);
   mongoc_collection_drop (collection, NULL);
   mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &doc, NULL, NULL);
   /* duplicate key error on the second insert */
   mongoc_collection_insert (collection, MONGOC_INSERT_NONE, &doc, NULL, NULL);

   printf ("started: %d\nsucceeded: %d\nfailed: %d\n",
           stats.started, stats.succeeded, stats.failed);

   bson_destroy (&doc);
   mongoc_collection_destroy (collection);
   mongoc_apm_callbacks_destroy (callbacks);
   mongoc_client_destroy (client);

   mongoc_cleanup ();

   return EXIT_SUCCESS;
}

This example program prints:

Command drop started on 127.0.0.1:
{ "drop" : "test" }

Command drop failed:
"ns not found"

Command insert started on 127.0.0.1:
{ "insert" : "test", "documents" : [ { "_id" : 1 } ] }

Command insert succeeded:
{ "ok" : 1, "n" : 1 }

Command insert started on 127.0.0.1:
{ "insert" : "test", "documents" : [ { "_id" : 1 } ] }

Command insert succeeded:
{ "ok" : 1,
  "n" : 0,
  "writeErrors" : [ {
     "index" : 0, "code" : 11000,
     "errmsg" : "E11000 duplicate key error"
} ] }

started: 3
succeeded: 2
failed: 1

In older versions of the MongoDB wire protocol, queries and write operations are sent to the server with special opcodes , not as commands. To provide consistent event notifications with any MongoDB version, these legacy opcodes are reported as if they had used modern commands.

The final "insert" command is considered successful, despite the writeError, because the server replied to the overall command with ok : 1

Sdam Monitoring Example

/* gcc example‐sdam‐monitoring.c ‐o example‐sdam‐monitoring \
 *     $(pkg‐config ‐‐cflags ‐‐libs libmongoc‐1.0) */

/* ./example‐sdam‐monitoring [CONNECTION_STRING] */

#include <mongoc.h>
#include <stdio.h>

typedef struct
{
   int server_changed_events;
   int server_opening_events;
   int server_closed_events;
   int topology_changed_events;
   int topology_opening_events;
   int topology_closed_events;
   int heartbeat_started_events;
   int heartbeat_succeeded_events;
   int heartbeat_failed_events;
} stats_t;

static void
server_changed (const mongoc_apm_server_changed_t *event)
{
   stats_t *context;
   const mongoc_server_description_t *prev_sd, *new_sd;

   context = (stats_t *) mongoc_apm_server_changed_get_context (event);
   context‐>server_changed_events++;

   prev_sd = mongoc_apm_server_changed_get_previous_description (event);
   new_sd = mongoc_apm_server_changed_get_new_description (event);

   printf (
      "server changed: %s %s ‐> %s\n",
      mongoc_apm_server_changed_get_host (event)‐>host_and_port,
      mongoc_server_description_type (prev_sd),
      mongoc_server_description_type (new_sd));
}

static void
server_opening (const mongoc_apm_server_opening_t *event)
{
   stats_t *context;

   context = (stats_t *) mongoc_apm_server_opening_get_context (event);
   context‐>server_opening_events++;

   printf ("server opening: %s\n",
           mongoc_apm_server_opening_get_host (event)‐>host_and_port);
}

static void
server_closed (const mongoc_apm_server_closed_t *event)
{
   stats_t *context;

   context = (stats_t *) mongoc_apm_server_closed_get_context (event);
   context‐>server_closed_events++;

   printf ("server closed: %s\n",
           mongoc_apm_server_closed_get_host (event)‐>host_and_port);
}

static void
topology_changed (const mongoc_apm_topology_changed_t *event)
{
   stats_t *context;
   const mongoc_topology_description_t *prev_td;
   const mongoc_topology_description_t *new_td;
   mongoc_server_description_t **prev_sds;
   size_t n_prev_sds;
   mongoc_server_description_t **new_sds;
   size_t n_new_sds;
   size_t i;

   context = (stats_t *) mongoc_apm_topology_changed_get_context (event);
   context‐>topology_changed_events++;

   prev_td = mongoc_apm_topology_changed_get_previous_description (event);
   prev_sds = mongoc_topology_description_get_servers (prev_td, &n_prev_sds);
   new_td = mongoc_apm_topology_changed_get_new_description (event);
   new_sds = mongoc_topology_description_get_servers (new_td, &n_new_sds);

   printf ("topology changed: %s ‐> %s\n",
           mongoc_topology_description_type (prev_td),
           mongoc_topology_description_type (new_td));

   if (n_prev_sds) {
      printf ("  previous servers:\n");
      for (i = 0; i < n_prev_sds; i++) {
         printf ("      %s %s\n",
                 mongoc_server_description_type (prev_sds[i]),
                 mongoc_server_description_host (prev_sds[i])‐>host_and_port);
      }
   }

   if (n_new_sds) {
      printf ("  new servers:\n");
      for (i = 0; i < n_new_sds; i++) {
         printf ("      %s %s\n",
                 mongoc_server_description_type (new_sds[i]),
                 mongoc_server_description_host (new_sds[i])‐>host_and_port);
      }
   }

   mongoc_server_descriptions_destroy_all (prev_sds, n_prev_sds);
   mongoc_server_descriptions_destroy_all (new_sds, n_new_sds);
}

static void
topology_opening (const mongoc_apm_topology_opening_t *event)
{
   stats_t *context;

   context = (stats_t *) mongoc_apm_topology_opening_get_context (event);
   context‐>topology_opening_events++;

   printf ("topology opening\n");
}

static void
topology_closed (const mongoc_apm_topology_closed_t *event)
{
   stats_t *context;

   context = (stats_t *) mongoc_apm_topology_closed_get_context (event);
   context‐>topology_closed_events++;

   printf ("topology closed\n");
}

static void
server_heartbeat_started (const mongoc_apm_server_heartbeat_started_t *event)
{
   stats_t *context;

   context =
      (stats_t *) mongoc_apm_server_heartbeat_started_get_context (event);
   context‐>heartbeat_started_events++;

   printf (
      "%s heartbeat started\n",
      mongoc_apm_server_heartbeat_started_get_host (event)‐>host_and_port);
}

static void
server_heartbeat_succeeded (const mongoc_apm_server_heartbeat_succeeded_t *event)
{
   stats_t *context;
   char *reply;

   context = (stats_t *) mongoc_apm_server_heartbeat_succeeded_get_context (
      event);
   context‐>heartbeat_succeeded_events++;

   reply = bson_as_json (
      mongoc_apm_server_heartbeat_succeeded_get_reply (event), NULL);

   printf (
      "%s heartbeat succeeded: %s\n",
      mongoc_apm_server_heartbeat_succeeded_get_host (event)‐>host_and_port,
      reply);

   bson_free (reply);
}

static void
server_heartbeat_failed (const mongoc_apm_server_heartbeat_failed_t *event)
{
   stats_t *context;
   bson_error_t error;

   context = (stats_t *) mongoc_apm_server_heartbeat_failed_get_context (event);
   context‐>heartbeat_failed_events++;
   mongoc_apm_server_heartbeat_failed_get_error (event, &error);

   printf (
      "%s heartbeat failed: %s\n",
      mongoc_apm_server_heartbeat_failed_get_host (event)‐>host_and_port,
      error.message);
}

int
main (int   argc,
      char *argv[])
{
   mongoc_client_t *client;
   mongoc_apm_callbacks_t *cbs;
   stats_t stats = { 0 };
   const char *uristr = "mongodb://127.0.0.1/?appname=sdam‐monitoring‐example";
   bson_t cmd = BSON_INITIALIZER;
   bson_t reply;
   bson_error_t error;

   mongoc_init ();

   if (argc > 1) {
      uristr = argv [1];
   }

   client = mongoc_client_new (uristr);

   if (!client) {
      fprintf (stderr, "Failed to parse URI.\n");
      return EXIT_FAILURE;
   }

   mongoc_client_set_error_api (client, 2);
   cbs = mongoc_apm_callbacks_new ();
   mongoc_apm_set_server_changed_cb (cbs, server_changed);
   mongoc_apm_set_server_opening_cb (cbs, server_opening);
   mongoc_apm_set_server_closed_cb (cbs, server_closed);
   mongoc_apm_set_topology_changed_cb (cbs, topology_changed);
   mongoc_apm_set_topology_opening_cb (cbs, topology_opening);
   mongoc_apm_set_topology_closed_cb (cbs, topology_closed);
   mongoc_apm_set_server_heartbeat_started_cb (cbs, server_heartbeat_started);
   mongoc_apm_set_server_heartbeat_succeeded_cb (cbs,
                                                 server_heartbeat_succeeded);
   mongoc_apm_set_server_heartbeat_failed_cb (cbs, server_heartbeat_failed);
   mongoc_client_set_apm_callbacks (client, cbs,
                                    (void *) &stats /* context pointer */);

   /* the driver connects on demand to perform first operation */
   BSON_APPEND_INT32 (&cmd, "buildinfo", 1);
   mongoc_client_command_simple (client, "admin", &cmd, NULL, &reply, &error);
   mongoc_client_destroy (client);

   printf ("Events:\n"
           "   server changed: %d\n"
           "   server opening: %d\n"
           "   server closed: %d\n"
           "   topology changed: %d\n"
           "   topology opening: %d\n"
           "   topology closed: %d\n"
           "   heartbeat started: %d\n"
           "   heartbeat succeeded: %d\n"
           "   heartbeat failed: %d\n",
           stats.server_changed_events,
           stats.server_opening_events,
           stats.server_closed_events,
           stats.topology_changed_events,
           stats.topology_opening_events,
           stats.topology_closed_events,
           stats.heartbeat_started_events,
           stats.heartbeat_succeeded_events,
           stats.heartbeat_failed_events);

   bson_destroy (&cmd);
   bson_destroy (&reply);
   mongoc_apm_callbacks_destroy (cbs);

   mongoc_cleanup ();

   return EXIT_SUCCESS;
}

Start a 3‐node replica set on localhost with set name "rs" and start the program:

./example-sdam-monitoring mongodb://localhost:27017,localhost:27018/?replicaSet=rs

This example program prints something like:

topology opening
topology changed: Unknown ‐> ReplicaSetNoPrimary
server opening: localhost:27017
server opening: localhost:27018
localhost:27017 heartbeat started
localhost:27018 heartbeat started
localhost:27017 heartbeat succeeded: { ... reply ... }
server changed: localhost:27017 Unknown ‐> RSPrimary
server opening: localhost:27019
topology changed: ReplicaSetNoPrimary ‐> ReplicaSetWithPrimary
  new servers:
      RSPrimary localhost:27017
localhost:27019 heartbeat started
localhost:27018 heartbeat succeeded: { ... reply ... }
server changed: localhost:27018 Unknown ‐> RSSecondary
topology changed: ReplicaSetWithPrimary ‐> ReplicaSetWithPrimary
  previous servers:
      RSPrimary localhost:27017
  new servers:
      RSPrimary localhost:27017
      RSSecondary localhost:27018
localhost:27019 heartbeat succeeded: { ... reply ... }
server changed: localhost:27019 Unknown ‐> RSSecondary
topology changed: ReplicaSetWithPrimary ‐> ReplicaSetWithPrimary
  previous servers:
      RSPrimary localhost:27017
      RSSecondary localhost:27018
  new servers:
      RSPrimary localhost:27017
      RSSecondary localhost:27018
      RSSecondary localhost:27019
topology closed

Events:
   server changed: 3
   server opening: 3
   server closed: 0
   topology changed: 4
   topology opening: 1
   topology closed: 1
   heartbeat started: 3
   heartbeat succeeded: 3
   heartbeat failed: 0

The driver discovers the third member, "localhost:27019", and adds it to the topology.

Colophon

This page is part of MongoDB C Driver. Please report any bugs at https://jira.mongodb.org/browse/CDRIVER.

Info

2016‐11‐07 MongoDB C Driver