1MONGOC_APPLICATION_PERFORMANCE_MONIMTlOOiNRbGImONoCGn_(gA3oP)cPLICATION_PERFORMANCE_MONITORING(3)
2
3
4
5The MongoDB C Driver allows you to monitor all the MongoDB operations the
6driver executes. This event-notification system conforms to two MongoDB driver
7specs:
8
9 • Command Logging and Monitoring: events related to all application op‐
10 erations.
11
12 • SDAM Monitoring: events related to the driver's Server Discovery And
13 Monitoring logic.
14
15 To receive notifications, create a mongoc_apm_callbacks_t with
16 mongoc_apm_callbacks_new(), set callbacks on it, then pass it to
17 mongoc_client_set_apm_callbacks() or
18 mongoc_client_pool_set_apm_callbacks().
19
21 example-command-monitoring.c
22
23 /* gcc example-command-monitoring.c -o example-command-monitoring \
24 * $(pkg-config --cflags --libs libmongoc-1.0) */
25
26 /* ./example-command-monitoring [CONNECTION_STRING] */
27
28 #include <mongoc/mongoc.h>
29 #include <stdio.h>
30
31
32 typedef struct {
33 int started;
34 int succeeded;
35 int failed;
36 } stats_t;
37
38
39 void
40 command_started (const mongoc_apm_command_started_t *event)
41 {
42 char *s;
43
44 s = bson_as_relaxed_extended_json (
45 mongoc_apm_command_started_get_command (event), NULL);
46 printf ("Command %s started on %s:\n%s\n\n",
47 mongoc_apm_command_started_get_command_name (event),
48 mongoc_apm_command_started_get_host (event)->host,
49 s);
50
51 ((stats_t *) mongoc_apm_command_started_get_context (event))->started++;
52
53 bson_free (s);
54 }
55
56
57 void
58 command_succeeded (const mongoc_apm_command_succeeded_t *event)
59 {
60 char *s;
61
62 s = bson_as_relaxed_extended_json (
63 mongoc_apm_command_succeeded_get_reply (event), NULL);
64 printf ("Command %s succeeded:\n%s\n\n",
65 mongoc_apm_command_succeeded_get_command_name (event),
66 s);
67
68 ((stats_t *) mongoc_apm_command_succeeded_get_context (event))->succeeded++;
69
70 bson_free (s);
71 }
72
73
74 void
75 command_failed (const mongoc_apm_command_failed_t *event)
76 {
77 bson_error_t error;
78
79 mongoc_apm_command_failed_get_error (event, &error);
80 printf ("Command %s failed:\n\"%s\"\n\n",
81 mongoc_apm_command_failed_get_command_name (event),
82 error.message);
83
84 ((stats_t *) mongoc_apm_command_failed_get_context (event))->failed++;
85 }
86
87
88 int
89 main (int argc, char *argv[])
90 {
91 mongoc_client_t *client;
92 mongoc_apm_callbacks_t *callbacks;
93 stats_t stats = {0};
94 mongoc_collection_t *collection;
95 bson_error_t error;
96 const char *uri_string =
97 "mongodb://127.0.0.1/?appname=cmd-monitoring-example";
98 mongoc_uri_t *uri;
99 const char *collection_name = "test";
100 bson_t *docs[2];
101
102 mongoc_init ();
103
104 if (argc > 1) {
105 uri_string = argv[1];
106 }
107
108 uri = mongoc_uri_new_with_error (uri_string, &error);
109 if (!uri) {
110 fprintf (stderr,
111 "failed to parse URI: %s\n"
112 "error message: %s\n",
113 uri_string,
114 error.message);
115 return EXIT_FAILURE;
116 }
117
118 client = mongoc_client_new_from_uri (uri);
119 if (!client) {
120 return EXIT_FAILURE;
121 }
122
123 mongoc_client_set_error_api (client, 2);
124 callbacks = mongoc_apm_callbacks_new ();
125 mongoc_apm_set_command_started_cb (callbacks, command_started);
126 mongoc_apm_set_command_succeeded_cb (callbacks, command_succeeded);
127 mongoc_apm_set_command_failed_cb (callbacks, command_failed);
128 mongoc_client_set_apm_callbacks (
129 client, callbacks, (void *) &stats /* context pointer */);
130
131 collection = mongoc_client_get_collection (client, "test", collection_name);
132 mongoc_collection_drop (collection, NULL);
133
134 docs[0] = BCON_NEW ("_id", BCON_INT32 (0));
135 docs[1] = BCON_NEW ("_id", BCON_INT32 (1));
136 mongoc_collection_insert_many (
137 collection, (const bson_t **) docs, 2, NULL, NULL, NULL);
138
139 /* duplicate key error on the second insert */
140 mongoc_collection_insert_one (collection, docs[0], NULL, NULL, NULL);
141
142 mongoc_collection_destroy (collection);
143 mongoc_apm_callbacks_destroy (callbacks);
144 mongoc_uri_destroy (uri);
145 mongoc_client_destroy (client);
146
147 printf ("started: %d\nsucceeded: %d\nfailed: %d\n",
148 stats.started,
149 stats.succeeded,
150 stats.failed);
151
152 bson_destroy (docs[0]);
153 bson_destroy (docs[1]);
154
155 mongoc_cleanup ();
156
157 return EXIT_SUCCESS;
158 }
159
160
161 This example program prints:
162
163 Command drop started on 127.0.0.1:
164 { "drop" : "test" }
165
166 Command drop succeeded:
167 { "ns" : "test.test", "nIndexesWas" : 1, "ok" : 1.0 }
168
169 Command insert started on 127.0.0.1:
170 {
171 "insert" : "test",
172 "ordered" : true,
173 "documents" : [
174 { "_id" : 0 }, { "_id" : 1 }
175 ]
176 }
177
178 Command insert succeeded:
179 { "n" : 2, "ok" : 1.0 }
180
181 Command insert started on 127.0.0.1:
182 {
183 "insert" : "test",
184 "ordered" : true,
185 "documents" : [
186 { "_id" : 0 }
187 ]
188 }
189
190 Command insert succeeded:
191 {
192 "n" : 0,
193 "writeErrors" : [
194 { "index" : 0, "code" : 11000, "errmsg" : "duplicate key" }
195 ],
196 "ok" : 1.0
197 }
198
199 started: 3
200 succeeded: 3
201 failed: 0
202
203 The output has been edited and formatted for clarity. Depending on your
204 server configuration, messages may include metadata like database name,
205 logical session ids, or cluster times that are not shown here.
206
207 The final "insert" command is considered successful, despite the
208 writeError, because the server replied to the overall command with
209 "ok": 1.
210
212 example-sdam-monitoring.c
213
214 /* gcc example-sdam-monitoring.c -o example-sdam-monitoring \
215 * $(pkg-config --cflags --libs libmongoc-1.0) */
216
217 /* ./example-sdam-monitoring [CONNECTION_STRING] */
218
219 #include <mongoc/mongoc.h>
220 #include <stdio.h>
221
222
223 typedef struct {
224 int server_changed_events;
225 int server_opening_events;
226 int server_closed_events;
227 int topology_changed_events;
228 int topology_opening_events;
229 int topology_closed_events;
230 int heartbeat_started_events;
231 int heartbeat_succeeded_events;
232 int heartbeat_failed_events;
233 } stats_t;
234
235
236 static void
237 server_changed (const mongoc_apm_server_changed_t *event)
238 {
239 stats_t *context;
240 const mongoc_server_description_t *prev_sd, *new_sd;
241
242 context = (stats_t *) mongoc_apm_server_changed_get_context (event);
243 context->server_changed_events++;
244
245 prev_sd = mongoc_apm_server_changed_get_previous_description (event);
246 new_sd = mongoc_apm_server_changed_get_new_description (event);
247
248 printf ("server changed: %s %s -> %s\n",
249 mongoc_apm_server_changed_get_host (event)->host_and_port,
250 mongoc_server_description_type (prev_sd),
251 mongoc_server_description_type (new_sd));
252 }
253
254
255 static void
256 server_opening (const mongoc_apm_server_opening_t *event)
257 {
258 stats_t *context;
259
260 context = (stats_t *) mongoc_apm_server_opening_get_context (event);
261 context->server_opening_events++;
262
263 printf ("server opening: %s\n",
264 mongoc_apm_server_opening_get_host (event)->host_and_port);
265 }
266
267
268 static void
269 server_closed (const mongoc_apm_server_closed_t *event)
270 {
271 stats_t *context;
272
273 context = (stats_t *) mongoc_apm_server_closed_get_context (event);
274 context->server_closed_events++;
275
276 printf ("server closed: %s\n",
277 mongoc_apm_server_closed_get_host (event)->host_and_port);
278 }
279
280
281 static void
282 topology_changed (const mongoc_apm_topology_changed_t *event)
283 {
284 stats_t *context;
285 const mongoc_topology_description_t *prev_td;
286 const mongoc_topology_description_t *new_td;
287 mongoc_server_description_t **prev_sds;
288 size_t n_prev_sds;
289 mongoc_server_description_t **new_sds;
290 size_t n_new_sds;
291 size_t i;
292 mongoc_read_prefs_t *prefs;
293
294 context = (stats_t *) mongoc_apm_topology_changed_get_context (event);
295 context->topology_changed_events++;
296
297 prev_td = mongoc_apm_topology_changed_get_previous_description (event);
298 prev_sds = mongoc_topology_description_get_servers (prev_td, &n_prev_sds);
299 new_td = mongoc_apm_topology_changed_get_new_description (event);
300 new_sds = mongoc_topology_description_get_servers (new_td, &n_new_sds);
301
302 printf ("topology changed: %s -> %s\n",
303 mongoc_topology_description_type (prev_td),
304 mongoc_topology_description_type (new_td));
305
306 if (n_prev_sds) {
307 printf (" previous servers:\n");
308 for (i = 0; i < n_prev_sds; i++) {
309 printf (" %s %s\n",
310 mongoc_server_description_type (prev_sds[i]),
311 mongoc_server_description_host (prev_sds[i])->host_and_port);
312 }
313 }
314
315 if (n_new_sds) {
316 printf (" new servers:\n");
317 for (i = 0; i < n_new_sds; i++) {
318 printf (" %s %s\n",
319 mongoc_server_description_type (new_sds[i]),
320 mongoc_server_description_host (new_sds[i])->host_and_port);
321 }
322 }
323
324 prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY);
325
326 /* it is safe, and unfortunately necessary, to cast away const here */
327 if (mongoc_topology_description_has_readable_server (
328 (mongoc_topology_description_t *) new_td, prefs)) {
329 printf (" secondary AVAILABLE\n");
330 } else {
331 printf (" secondary UNAVAILABLE\n");
332 }
333
334 if (mongoc_topology_description_has_writable_server (
335 (mongoc_topology_description_t *) new_td)) {
336 printf (" primary AVAILABLE\n");
337 } else {
338 printf (" primary UNAVAILABLE\n");
339 }
340
341 mongoc_read_prefs_destroy (prefs);
342 mongoc_server_descriptions_destroy_all (prev_sds, n_prev_sds);
343 mongoc_server_descriptions_destroy_all (new_sds, n_new_sds);
344 }
345
346
347 static void
348 topology_opening (const mongoc_apm_topology_opening_t *event)
349 {
350 stats_t *context;
351
352 context = (stats_t *) mongoc_apm_topology_opening_get_context (event);
353 context->topology_opening_events++;
354
355 printf ("topology opening\n");
356 }
357
358
359 static void
360 topology_closed (const mongoc_apm_topology_closed_t *event)
361 {
362 stats_t *context;
363
364 context = (stats_t *) mongoc_apm_topology_closed_get_context (event);
365 context->topology_closed_events++;
366
367 printf ("topology closed\n");
368 }
369
370
371 static void
372 server_heartbeat_started (const mongoc_apm_server_heartbeat_started_t *event)
373 {
374 stats_t *context;
375
376 context =
377 (stats_t *) mongoc_apm_server_heartbeat_started_get_context (event);
378 context->heartbeat_started_events++;
379
380 printf ("%s heartbeat started\n",
381 mongoc_apm_server_heartbeat_started_get_host (event)->host_and_port);
382 }
383
384
385 static void
386 server_heartbeat_succeeded (
387 const mongoc_apm_server_heartbeat_succeeded_t *event)
388 {
389 stats_t *context;
390 char *reply;
391
392 context =
393 (stats_t *) mongoc_apm_server_heartbeat_succeeded_get_context (event);
394 context->heartbeat_succeeded_events++;
395
396 reply = bson_as_canonical_extended_json (
397 mongoc_apm_server_heartbeat_succeeded_get_reply (event), NULL);
398
399 printf (
400 "%s heartbeat succeeded: %s\n",
401 mongoc_apm_server_heartbeat_succeeded_get_host (event)->host_and_port,
402 reply);
403
404 bson_free (reply);
405 }
406
407
408 static void
409 server_heartbeat_failed (const mongoc_apm_server_heartbeat_failed_t *event)
410 {
411 stats_t *context;
412 bson_error_t error;
413
414 context = (stats_t *) mongoc_apm_server_heartbeat_failed_get_context (event);
415 context->heartbeat_failed_events++;
416 mongoc_apm_server_heartbeat_failed_get_error (event, &error);
417
418 printf ("%s heartbeat failed: %s\n",
419 mongoc_apm_server_heartbeat_failed_get_host (event)->host_and_port,
420 error.message);
421 }
422
423
424 int
425 main (int argc, char *argv[])
426 {
427 mongoc_client_t *client;
428 mongoc_apm_callbacks_t *cbs;
429 stats_t stats = {0};
430 const char *uri_string =
431 "mongodb://127.0.0.1/?appname=sdam-monitoring-example";
432 mongoc_uri_t *uri;
433 bson_t cmd = BSON_INITIALIZER;
434 bson_t reply;
435 bson_error_t error;
436
437 mongoc_init ();
438
439 if (argc > 1) {
440 uri_string = argv[1];
441 }
442
443 uri = mongoc_uri_new_with_error (uri_string, &error);
444 if (!uri) {
445 fprintf (stderr,
446 "failed to parse URI: %s\n"
447 "error message: %s\n",
448 uri_string,
449 error.message);
450 return EXIT_FAILURE;
451 }
452
453 client = mongoc_client_new_from_uri (uri);
454 if (!client) {
455 return EXIT_FAILURE;
456 }
457
458 mongoc_client_set_error_api (client, 2);
459 cbs = mongoc_apm_callbacks_new ();
460 mongoc_apm_set_server_changed_cb (cbs, server_changed);
461 mongoc_apm_set_server_opening_cb (cbs, server_opening);
462 mongoc_apm_set_server_closed_cb (cbs, server_closed);
463 mongoc_apm_set_topology_changed_cb (cbs, topology_changed);
464 mongoc_apm_set_topology_opening_cb (cbs, topology_opening);
465 mongoc_apm_set_topology_closed_cb (cbs, topology_closed);
466 mongoc_apm_set_server_heartbeat_started_cb (cbs, server_heartbeat_started);
467 mongoc_apm_set_server_heartbeat_succeeded_cb (cbs,
468 server_heartbeat_succeeded);
469 mongoc_apm_set_server_heartbeat_failed_cb (cbs, server_heartbeat_failed);
470 mongoc_client_set_apm_callbacks (
471 client, cbs, (void *) &stats /* context pointer */);
472
473 /* the driver connects on demand to perform first operation */
474 BSON_APPEND_INT32 (&cmd, "buildinfo", 1);
475 mongoc_client_command_simple (client, "admin", &cmd, NULL, &reply, &error);
476 mongoc_uri_destroy (uri);
477 mongoc_client_destroy (client);
478
479 printf ("Events:\n"
480 " server changed: %d\n"
481 " server opening: %d\n"
482 " server closed: %d\n"
483 " topology changed: %d\n"
484 " topology opening: %d\n"
485 " topology closed: %d\n"
486 " heartbeat started: %d\n"
487 " heartbeat succeeded: %d\n"
488 " heartbeat failed: %d\n",
489 stats.server_changed_events,
490 stats.server_opening_events,
491 stats.server_closed_events,
492 stats.topology_changed_events,
493 stats.topology_opening_events,
494 stats.topology_closed_events,
495 stats.heartbeat_started_events,
496 stats.heartbeat_succeeded_events,
497 stats.heartbeat_failed_events);
498
499 bson_destroy (&cmd);
500 bson_destroy (&reply);
501 mongoc_apm_callbacks_destroy (cbs);
502
503 mongoc_cleanup ();
504
505 return EXIT_SUCCESS;
506 }
507
508
509 Start a 3-node replica set on localhost with set name "rs" and start
510 the program:
511
512 ./example-sdam-monitoring "mongodb://localhost:27017,localhost:27018/?replicaSet=rs"
513
514 This example program prints something like:
515
516 topology opening
517 topology changed: Unknown -> ReplicaSetNoPrimary
518 secondary UNAVAILABLE
519 primary UNAVAILABLE
520 server opening: localhost:27017
521 server opening: localhost:27018
522 localhost:27017 heartbeat started
523 localhost:27018 heartbeat started
524 localhost:27017 heartbeat succeeded: { ... reply ... }
525 server changed: localhost:27017 Unknown -> RSPrimary
526 server opening: localhost:27019
527 topology changed: ReplicaSetNoPrimary -> ReplicaSetWithPrimary
528 new servers:
529 RSPrimary localhost:27017
530 secondary UNAVAILABLE
531 primary AVAILABLE
532 localhost:27019 heartbeat started
533 localhost:27018 heartbeat succeeded: { ... reply ... }
534 server changed: localhost:27018 Unknown -> RSSecondary
535 topology changed: ReplicaSetWithPrimary -> ReplicaSetWithPrimary
536 previous servers:
537 RSPrimary localhost:27017
538 new servers:
539 RSPrimary localhost:27017
540 RSSecondary localhost:27018
541 secondary AVAILABLE
542 primary AVAILABLE
543 localhost:27019 heartbeat succeeded: { ... reply ... }
544 server changed: localhost:27019 Unknown -> RSSecondary
545 topology changed: ReplicaSetWithPrimary -> ReplicaSetWithPrimary
546 previous servers:
547 RSPrimary localhost:27017
548 RSSecondary localhost:27018
549 new servers:
550 RSPrimary localhost:27017
551 RSSecondary localhost:27018
552 RSSecondary localhost:27019
553 secondary AVAILABLE
554 primary AVAILABLE
555 topology closed
556
557 Events:
558 server changed: 3
559 server opening: 3
560 server closed: 0
561 topology changed: 4
562 topology opening: 1
563 topology closed: 1
564 heartbeat started: 3
565 heartbeat succeeded: 3
566 heartbeat failed: 0
567
568 The driver connects to the mongods on ports 27017 and 27018, which were
569 specified in the URI, and determines which is primary. It also discov‐
570 ers the third member, "localhost:27019", and adds it to the topology.
571
573 MongoDB, Inc
574
576 2017-present, MongoDB, Inc
577
578
579
580
5811.25.1 NoMvON0G8O,C_2A0P2P3LICATION_PERFORMANCE_MONITORING(3)