Skip site navigation (1)Skip section navigation (2)

  
 
  

home | help
MONGOC_APPLIC...NCE_MONITORING(3)   libmongoc  MONGOC_APPLIC...NCE_MONITORING(3)

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	Logging and Monitoring: events related to all application opera-
       tions.

     * SDAM Monitoring: events related to the driver's Server Discovery And Mon-
       itoring 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 writeEr-
     ror, 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);

	   if (mongoc_topology_description_has_readable_server (new_td, prefs)) {
	      printf ("  secondary AVAILABLE\n");
	   } else {
	      printf ("  secondary UNAVAILABLE\n");
	   }

	   if (mongoc_topology_description_has_writable_server (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
     2009-present, MongoDB, Inc.

1.30.8				  Aug 27, 2026 MONGOC_APPLIC...NCE_MONITORING(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=mongoc_application_performance_monitoring&sektion=3&manpath=FreeBSD+Ports+15.1.quarterly>

home | help