Provided by: libmongoc-doc_1.22.1-1_all bug

NAME

       mongoc_application_performance_monitoring - Application Performance Monitoring (APM)

       The MongoDB C Driver allows you to monitor all the MongoDB operations the driver executes.
       This event-notification system conforms to two MongoDB driver specs:

       • Command Monitoring: events related to all application operations.

       • SDAM Monitoring: events related to the driver's Server Discovery And Monitoring logic.

       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().

COMMAND-MONITORING EXAMPLE

       example-command-monitoring.c

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

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

          #include <mongoc/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_relaxed_extended_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_relaxed_extended_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;
             bson_error_t error;
             const char *uri_string =
                "mongodb://127.0.0.1/?appname=cmd-monitoring-example";
             mongoc_uri_t *uri;
             const char *collection_name = "test";
             bson_t *docs[2];

             mongoc_init ();

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

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                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 */);

             collection = mongoc_client_get_collection (client, "test", collection_name);
             mongoc_collection_drop (collection, NULL);

             docs[0] = BCON_NEW ("_id", BCON_INT32 (0));
             docs[1] = BCON_NEW ("_id", BCON_INT32 (1));
             mongoc_collection_insert_many (
                collection, (const bson_t **) docs, 2, NULL, NULL, NULL);

             /* duplicate key error on the second insert */
             mongoc_collection_insert_one (collection, docs[0], NULL, NULL, NULL);

             mongoc_collection_destroy (collection);
             mongoc_apm_callbacks_destroy (callbacks);
             mongoc_uri_destroy (uri);
             mongoc_client_destroy (client);

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

             bson_destroy (docs[0]);
             bson_destroy (docs[1]);

             mongoc_cleanup ();

             return EXIT_SUCCESS;
          }

       This example program prints:

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

          Command drop succeeded:
          { "ns" : "test.test", "nIndexesWas" : 1, "ok" : 1.0 }

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

          Command insert succeeded:
          { "n" : 2, "ok" : 1.0 }

          Command insert started on 127.0.0.1:
          {
            "insert" : "test",
            "ordered" : true,
            "documents" : [
              { "_id" : 0 }
            ]
          }

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

          started: 3
          succeeded: 3
          failed: 0

       The  output  has  been  edited  and  formatted  for  clarity.  Depending  on  your  server
       configuration,  messages  may include metadata like database name, logical session ids, or
       cluster times that are not shown here.

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

SDAM MONITORING EXAMPLE

       example-sdam-monitoring.c

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

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

          #include <mongoc/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;
             mongoc_read_prefs_t *prefs;

             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);
                }
             }

             prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);

             /* it is safe, and unfortunately necessary, to cast away const here */
             if (mongoc_topology_description_has_readable_server (
                    (mongoc_topology_description_t *) new_td, prefs)) {
                printf ("  secondary AVAILABLE\n");
             } else {
                printf ("  secondary UNAVAILABLE\n");
             }

             if (mongoc_topology_description_has_writable_server (
                    (mongoc_topology_description_t *) new_td)) {
                printf ("  primary AVAILABLE\n");
             } else {
                printf ("  primary UNAVAILABLE\n");
             }

             mongoc_read_prefs_destroy (prefs);
             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_canonical_extended_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 *uri_string =
                "mongodb://127.0.0.1/?appname=sdam-monitoring-example";
             mongoc_uri_t *uri;
             bson_t cmd = BSON_INITIALIZER;
             bson_t reply;
             bson_error_t error;

             mongoc_init ();

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

             uri = mongoc_uri_new_with_error (uri_string, &error);
             if (!uri) {
                fprintf (stderr,
                         "failed to parse URI: %s\n"
                         "error message:       %s\n",
                         uri_string,
                         error.message);
                return EXIT_FAILURE;
             }

             client = mongoc_client_new_from_uri (uri);
             if (!client) {
                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_uri_destroy (uri);
             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
            secondary UNAVAILABLE
            primary UNAVAILABLE
          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
            secondary UNAVAILABLE
            primary AVAILABLE
          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
            secondary AVAILABLE
            primary AVAILABLE
          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
            secondary AVAILABLE
            primary AVAILABLE
          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  connects to the mongods on ports 27017 and 27018, which were specified in the
       URI,  and  determines  which  is  primary.   It   also   discovers   the   third   member,
       "localhost:27019", and adds it to the topology.

AUTHOR

       MongoDB, Inc

COPYRIGHT

       2017-present, MongoDB, Inc

1.22.1                                     Aug 02, 20MONGOC_APPLICATION_PERFORMANCE_MONITORING(3)