Introduction to Application Performance Monitoring

The MongoDB C Driver allows you to monitor all the MongoDB operations the driver executes. This event-notification system conforms to the Command Monitoring Spec for MongoDB drivers.

To receive notifications, create a mongoc_apm_callbacks_t with mongoc_apm_callbacks_new, set callbacks on it, then pass it to mongoc_client_set_apm_callbacks or mongoc_client_pool_set_apm_callbacks.

APM Example

/* gcc example-application-performance-monitoring.c -o example-apm \
 *     $(pkg-config --cflags --libs libmongoc-1.0) */

/* ./example-apm [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/";
   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.