COMMAND-MONITORING EXAMPLE
- Provided by: libmongoc-doc (Version: 2.2.2-1)
- Source: mongo-c-driver
- Report a bug
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:
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() <>.
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.
MongoDB, Inc
2009-present, MongoDB, Inc.