Skip to content

Commit 51c7384

Browse files
committed
CDRIVER-2370 monitor OP_MSG document sequences
Update Command Monitoring (also known as APM) to expose the document sequence sent with an OP_MSG insert, update, or delete. Simulate a document sequence if the wire protocol uses OP_QUERY commands instead of OP_MSG. In MongoDB 3.8 there will be document sequences in the OP_MSG reply to "find", "aggregate", etc. Anticipate that wire protocol by simulating a document sequence with command replies.
1 parent 5a0018c commit 51c7384

14 files changed

+739
-45
lines changed

doc/application-performance-monitoring.rst

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,37 @@ This example program prints:
2222
.. code-block:: none
2323
2424
Command drop started on 127.0.0.1:
25-
{ "drop" : "test" }
25+
{ "drop" : "test", "$db" : "test" }
2626
27-
Command drop failed:
28-
"ns not found"
27+
Command drop succeeded:
28+
{ "ns" : "test.test", "nIndexesWas" : 1, "ok" : 1.0 }
2929
3030
Command insert started on 127.0.0.1:
31-
{ "insert" : "test", "documents" : [ { "_id" : 1 } ] }
31+
{ "insert" : "test", "ordered" : true, "$db" : "test" }
32+
document 0 { "_id" : 0 }
33+
document 1 { "_id" : 1 }
3234
3335
Command insert succeeded:
34-
{ "ok" : 1, "n" : 1 }
36+
{ "n" : 1, "ok" : 1.0 }
3537
3638
Command insert started on 127.0.0.1:
37-
{ "insert" : "test", "documents" : [ { "_id" : 1 } ] }
39+
{ "insert" : "test", "ordered" : true, "$db" : "test" }
40+
document 0: { "_id" : 1 }
3841
3942
Command insert succeeded:
40-
{ "ok" : 1,
43+
{
4144
"n" : 0,
42-
"writeErrors" : [ {
43-
"index" : 0, "code" : 11000,
44-
"errmsg" : "E11000 duplicate key error"
45-
} ] }
45+
"writeErrors" : [
46+
{ "index" : 0, "code" : 11000, "errmsg" : "duplicate key" }
47+
],
48+
"ok" : 1.0
49+
}
4650
47-
started: 3
48-
succeeded: 2
49-
failed: 1
51+
started: 4
52+
succeeded: 4
53+
failed: 0
5054
51-
In older versions of the MongoDB wire protocol, queries and write operations are sent to the server with special `opcodes <https://docs.mongodb.org/manual/reference/mongodb-wire-protocol/#request-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.
55+
(Depending on your server configuration, messages may include metadata like logical session ids or cluster times that are not shown here.)
5256

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

@@ -126,6 +130,7 @@ The driver discovers the third member, "localhost:27019", and adds it to the top
126130
:maxdepth: 1
127131

128132
mongoc_apm_callbacks_t
133+
mongoc_apm_document_sequence_t
129134
mongoc_apm_command_failed_t
130135
mongoc_apm_command_started_t
131136
mongoc_apm_command_succeeded_t
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
:man_page: mongoc_apm_command_started_get_document_sequences
2+
3+
mongoc_apm_command_started_get_document_sequences()
4+
===================================================
5+
6+
Synopsis
7+
--------
8+
9+
.. code-block:: c
10+
11+
void
12+
mongoc_apm_command_started_get_document_sequences (
13+
const mongoc_apm_command_started_t *event,
14+
const mongoc_apm_document_sequence_t **sequences,
15+
size_t *n_sequences);
16+
17+
Returns the document sequences sent to the server with this command. The "insert", "update", and "delete" commands have one document sequence; for other commands sequences is NULL and the number of sequences is 0.
18+
19+
In MongoDB 3.4 and older, the "insert", "update", and "delete" commands include one document sequence as a BSON array within the command body. Starting in MongoDB 3.6, these commands each send one document sequence as a separate section of the OP_MSG, and the document sequence is not available in the command body. This function retrieves the document sequence sent to any version of MongoDB.
20+
21+
The data is only valid in the scope of the callback that receives this event; copy it if it will be accessed after the callback returns.
22+
23+
Parameters
24+
----------
25+
26+
* ``event``: A :symbol:`mongoc_apm_command_started_t`.
27+
* ``sequences``: An array of pointers to a :symbol:`mongoc_apm_document_sequence_t`.
28+
* ``n_sequences``: The number of document sequences sent with the command.
29+
30+
See Also
31+
--------
32+
33+
:doc:`Introduction to Application Performance Monitoring <application-performance-monitoring>`

doc/mongoc_apm_command_started_t.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ See Also
2828
mongoc_apm_command_started_get_command_name
2929
mongoc_apm_command_started_get_context
3030
mongoc_apm_command_started_get_database_name
31+
mongoc_apm_command_started_get_document_sequences
3132
mongoc_apm_command_started_get_host
3233
mongoc_apm_command_started_get_operation_id
3334
mongoc_apm_command_started_get_request_id
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
:man_page: mongoc_apm_command_succeeded_get_document_sequences
2+
3+
mongoc_apm_command_succeeded_get_document_sequences()
4+
=====================================================
5+
6+
Synopsis
7+
--------
8+
9+
.. code-block:: c
10+
11+
void
12+
mongoc_apm_command_succeeded_get_document_sequences (
13+
const mongoc_apm_command_succeeded_t *event,
14+
const mongoc_apm_document_sequence_t **sequences,
15+
size_t *n_sequences);
16+
17+
Returns the document sequences sent by the server. Query-like commands such as "find" and "aggregate" return one document sequence, for other commands the document sequence is NULL and the number of documents is 0.
18+
19+
In MongoDB 3.6 and older, all replies include their document sequences as BSON arrays within the reply body. Starting in MongoDB 3.8, document sequences are sent as separate sections of the OP_MSG, and are not available in the reply body. This function retrieves the document sequences sent by any version of MongoDB server.
20+
21+
The data is only valid in the scope of the callback that receives this event; copy it if it will be accessed after the callback returns.
22+
23+
Parameters
24+
----------
25+
26+
* ``event``: A :symbol:`mongoc_apm_command_succeeded_t`.
27+
* ``sequences``: An array of pointers to a :symbol:`mongoc_apm_document_sequence_t`.
28+
* ``n_sequences``: The number of document sequences sent with the command.
29+
30+
See Also
31+
--------
32+
33+
:doc:`Introduction to Application Performance Monitoring <application-performance-monitoring>`

doc/mongoc_apm_command_succeeded_t.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ See Also
2626

2727
mongoc_apm_command_succeeded_get_command_name
2828
mongoc_apm_command_succeeded_get_context
29+
mongoc_apm_command_succeeded_get_document_sequences
2930
mongoc_apm_command_succeeded_get_duration
3031
mongoc_apm_command_succeeded_get_host
3132
mongoc_apm_command_succeeded_get_operation_id
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
:man_page: mongoc_apm_document_sequence_t
2+
3+
mongoc_apm_document_sequence_t
4+
==============================
5+
6+
Synopsis
7+
--------
8+
9+
.. code-block:: c
10+
11+
typedef struct {
12+
int32_t size;
13+
const char *identifier;
14+
bson_t **documents;
15+
} mongoc_apm_document_sequence_t;
16+
17+
Used in Application Performance Monitoring to represent the sequence of BSON documents sent to MongoDB with an "insert", "update", or "delete" command, or to represent the sequence of documents returned by a "find" or "aggregate" command.
18+
19+
See Also
20+
--------
21+
22+
:doc:`Introduction to Application Performance Monitoring <application-performance-monitoring>`
23+
24+
.. only:: html
25+
26+
Functions
27+
---------
28+
29+
.. toctree::
30+
:titlesonly:
31+
:maxdepth: 1
32+
33+
mongoc_apm_command_started_get_document_sequences
34+
mongoc_apm_command_succeeded_get_document_sequences

examples/example-command-monitoring.c

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,65 @@ void
1818
command_started (const mongoc_apm_command_started_t *event)
1919
{
2020
char *s;
21+
const mongoc_apm_document_sequence_t *sequences;
22+
size_t n_sequences, i, j;
2123

22-
s = bson_as_canonical_extended_json (
24+
s = bson_as_relaxed_extended_json (
2325
mongoc_apm_command_started_get_command (event), NULL);
24-
printf ("Command %s started on %s:\n%s\n\n",
26+
27+
printf ("Command %s started on %s:\n%s\n",
2528
mongoc_apm_command_started_get_command_name (event),
2629
mongoc_apm_command_started_get_host (event)->host,
2730
s);
2831

29-
((stats_t *) mongoc_apm_command_started_get_context (event))->started++;
30-
3132
bson_free (s);
33+
34+
/* insert, update, and delete commands include a document sequence */
35+
mongoc_apm_command_started_get_document_sequences (
36+
event, &sequences, &n_sequences);
37+
38+
for (i = 0; i < n_sequences; i++) {
39+
for (j = 0; j < sequences[i].size; j++) {
40+
s = bson_as_relaxed_extended_json (sequences[i].documents[j], NULL);
41+
printf (" document %zi %s\n", j, s);
42+
bson_free (s);
43+
}
44+
}
45+
46+
((stats_t *) mongoc_apm_command_started_get_context (event))->started++;
3247
}
3348

3449

3550
void
3651
command_succeeded (const mongoc_apm_command_succeeded_t *event)
3752
{
3853
char *s;
54+
const mongoc_apm_document_sequence_t *sequences;
55+
size_t n_sequences, i, j;
3956

40-
s = bson_as_canonical_extended_json (
57+
s = bson_as_relaxed_extended_json (
4158
mongoc_apm_command_succeeded_get_reply (event), NULL);
42-
printf ("Command %s succeeded:\n%s\n\n",
59+
60+
printf ("Command %s succeeded on %s:\n%s\n",
4361
mongoc_apm_command_succeeded_get_command_name (event),
62+
mongoc_apm_command_succeeded_get_host (event)->host,
4463
s);
4564

46-
((stats_t *) mongoc_apm_command_succeeded_get_context (event))->succeeded++;
47-
4865
bson_free (s);
66+
67+
/* replies to "find" or "aggregate" include a document sequence */
68+
mongoc_apm_command_succeeded_get_document_sequences (
69+
event, &sequences, &n_sequences);
70+
71+
for (i = 0; i < n_sequences; i++) {
72+
for (j = 0; j < sequences[i].size; j++) {
73+
s = bson_as_relaxed_extended_json (sequences[i].documents[j], NULL);
74+
printf (" document %zi %s\n", j, s);
75+
bson_free (s);
76+
}
77+
}
78+
79+
((stats_t *) mongoc_apm_command_succeeded_get_context (event))->succeeded++;
4980
}
5081

5182

@@ -72,7 +103,7 @@ main (int argc, char *argv[])
72103
mongoc_collection_t *collection;
73104
const char *uristr = "mongodb://127.0.0.1/?appname=cmd-monitoring-example";
74105
const char *collection_name = "test";
75-
bson_t doc;
106+
bson_t *docs[2];
76107

77108
mongoc_init ();
78109

@@ -95,16 +126,17 @@ main (int argc, char *argv[])
95126
mongoc_client_set_apm_callbacks (
96127
client, callbacks, (void *) &stats /* context pointer */);
97128

98-
bson_init (&doc);
99-
BSON_APPEND_INT32 (&doc, "_id", 1);
100-
101129
collection = mongoc_client_get_collection (client, "test", collection_name);
102130
mongoc_collection_drop (collection, NULL);
103-
mongoc_collection_insert_one (collection, &doc, NULL, NULL, NULL);
131+
132+
docs[0] = BCON_NEW ("_id", BCON_INT32 (0));
133+
docs[1] = BCON_NEW ("_id", BCON_INT32 (1));
134+
mongoc_collection_insert_many (
135+
collection, (const bson_t **) docs, 2, NULL, NULL, NULL);
136+
104137
/* duplicate key error on the second insert */
105-
mongoc_collection_insert_one (collection, &doc, NULL, NULL, NULL);
138+
mongoc_collection_insert_one (collection, docs[0], NULL, NULL, NULL);
106139

107-
bson_destroy (&doc);
108140
mongoc_collection_destroy (collection);
109141
mongoc_apm_callbacks_destroy (callbacks);
110142
mongoc_client_destroy (client);
@@ -114,6 +146,9 @@ main (int argc, char *argv[])
114146
stats.succeeded,
115147
stats.failed);
116148

149+
bson_destroy (docs[0]);
150+
bson_destroy (docs[1]);
151+
117152
mongoc_cleanup ();
118153

119154
return EXIT_SUCCESS;

src/mongoc/mongoc-apm-private.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@
2323

2424
#include <bson.h>
2525
#include "mongoc-apm.h"
26+
#include "mongoc-array-private.h"
2627

2728
BSON_BEGIN_DECLS
2829

30+
/* forward decl */
31+
typedef struct _mongoc_cmd_t mongoc_cmd_t;
32+
2933
struct _mongoc_apm_callbacks_t {
3034
mongoc_apm_command_started_cb_t started;
3135
mongoc_apm_command_succeeded_cb_t succeeded;
@@ -54,6 +58,8 @@ struct _mongoc_apm_command_started_t {
5458
int64_t operation_id;
5559
const mongoc_host_list_t *host;
5660
uint32_t server_id;
61+
/* for now, an OP_MSG has at most one document sequence */
62+
mongoc_apm_document_sequence_t *sequence;
5763
void *context;
5864
};
5965

@@ -65,6 +71,7 @@ struct _mongoc_apm_command_succeeded_t {
6571
int64_t operation_id;
6672
const mongoc_host_list_t *host;
6773
uint32_t server_id;
74+
mongoc_apm_document_sequence_t *sequence;
6875
void *context;
6976
};
7077

@@ -150,6 +157,12 @@ mongoc_apm_command_started_init (mongoc_apm_command_started_t *event,
150157
uint32_t server_id,
151158
void *context);
152159

160+
void
161+
mongoc_apm_command_started_init_with_cmd (mongoc_apm_command_started_t *event,
162+
mongoc_cmd_t *cmd,
163+
int64_t request_id,
164+
void *context);
165+
153166
void
154167
mongoc_apm_command_started_cleanup (mongoc_apm_command_started_t *event);
155168

0 commit comments

Comments
 (0)