Skip to content

Commit a91d6f6

Browse files
authored
CDRIVER-4500: SDAM structured log and unified test support (#1842)
* Resolves CDRIVER-4500 (SDAM structured logs + updated unified tests) * Resolves CDRIVER-4758 (Prose test for heartbeat event order: /server_discovery_and_monitoring/prose/heartbeat) * Resolves CDRIVER-4137 (Missing server close events, now tested by /server_discovery_and_monitoring/unified) * Completes outstanding issues in the CDRIVER-3775 epic (libmongoc structured logging) Details: * Synchronized SDAM spec tests from the specifications repository, commit d795d493c41022cb8ed15006ae5ac5ad85936f40 * Added /server_discovery_and_monitoring/unified tests * Refactoring: new log-and-monitor type for apm monitoring state plus structured log instance * Implemented SDAM log messages for topology changes and monitoring lifecycle * Fixes for lifecycle events generated for Structured Log and APM consumers: * ServerOpeningEvent is deferred based on topology 'opening' state, not based on when callbacks are installed. * Required ServerClosedEvent and topology Unknown state changes are emitted prior to TopologyClosedEvent. * New Structured Log items: * oid() for a plain ObjectID without hex representation * topology_description_as_json() for plain topology descriptions not inside a topology * Added test skips for SDAM unified tests that require pool support, driver-generated connection IDs, thread entities. * Test skips for CDRIVER-5870 (Spec compliant response to authentication errors) * Additional debug output from loadbalancer tests * CDRIVER-4758: added /server_discovery_and_monitoring/prose/heartbeat * Unified test runner changes * Error instead of segfault when checking events/logs on missing client entity * Support for "closing" some entity types without deleting (For example, to inspect events logged when closing a client) * Added debug logging about log suppression * Added per-entity structured log filter stack (entity_map_log_filter_push/pop) used internally to refine the apparent behavior of waitForEvent * Added SDAM APM events, and a suitable eventType filtering implementation. * New operations: assertEventCount, recordTopologyDescription, assertTopologyType, waitForPrimaryChange * entity-map: pass server monitoring mode URI option * runCommand should report reply as result for matching * waitForEvent: do an entire stream-selection, to advance blocking topology scans * Fix entity-map destructor for findcursor without cursor
1 parent 2a35499 commit a91d6f6

File tree

167 files changed

+11432
-1505
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+11432
-1505
lines changed

NEWS

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
libmongoc 1.30.0 (Unreleased)
22
=============================
33

4+
Fixes:
5+
6+
* Additional APM events required by the SDAM specification will now be delivered:
7+
* Servers that have seen `server_opening` will now see a `server_closed` prior to `topology_closed`.
8+
* Before `topology_closed`, a `topology_changed` event will transition to `Unknown` topology type.
9+
410
Deprecated:
511

612
* Support for Debian 9 and Debian 10.

src/libmongoc/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ set (MONGOC_SOURCES
623623
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-list.c
624624
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-linux-distro-scanner.c
625625
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-log.c
626+
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-log-and-monitor-private.c
626627
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-matcher.c
627628
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-matcher-op.c
628629
${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-memcmp.c

src/libmongoc/src/mongoc/mongoc-client-pool.c

+20-29
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <mongoc/mongoc-client-pool.h>
2424
#include <mongoc/mongoc-client-private.h>
2525
#include <mongoc/mongoc-client-side-encryption-private.h>
26+
#include <mongoc/mongoc-log-and-monitor-private.h>
2627
#include <mongoc/mongoc-queue-private.h>
2728
#include <mongoc/mongoc-thread-private.h>
2829
#include <mongoc/mongoc-topology-private.h>
@@ -54,8 +55,6 @@ struct _mongoc_client_pool_t {
5455
bool error_api_set;
5556
bool structured_log_opts_set;
5657
bool client_initialized;
57-
mongoc_apm_callbacks_t apm_callbacks;
58-
void *apm_context;
5958
int32_t error_api_version;
6059
mongoc_server_api_t *api;
6160
// `last_known_serverids` is a sorted array of uint32_t.
@@ -283,7 +282,6 @@ _initialize_new_client (mongoc_client_pool_t *pool, mongoc_client_t *client)
283282

284283
pool->client_initialized = true;
285284
client->error_api_version = pool->error_api_version;
286-
_mongoc_client_set_apm_callbacks_private (client, &pool->apm_callbacks, pool->apm_context);
287285

288286
client->api = mongoc_server_api_copy (pool->api);
289287

@@ -577,35 +575,28 @@ bool
577575
mongoc_client_pool_set_apm_callbacks (mongoc_client_pool_t *pool, mongoc_apm_callbacks_t *callbacks, void *context)
578576
{
579577
BSON_ASSERT_PARAM (pool);
578+
BSON_OPTIONAL_PARAM (callbacks);
579+
BSON_OPTIONAL_PARAM (context);
580580

581-
mongoc_topology_t *const topology = BSON_ASSERT_PTR_INLINE (pool)->topology;
582-
mc_tpld_modification tdmod = mc_tpld_modify_begin (topology);
583-
584-
// Prevent setting callbacks more than once
581+
// Enforce documented thread-safety restrictions
585582
if (pool->apm_callbacks_set) {
586-
mc_tpld_modify_drop (tdmod);
587-
MONGOC_ERROR ("Can only set callbacks once");
583+
MONGOC_ERROR ("mongoc_client_pool_set_apm_callbacks can only be called once per pool");
588584
return false;
589-
}
585+
} else if (pool->client_initialized) {
586+
MONGOC_ERROR ("mongoc_client_pool_set_apm_callbacks can only be called before mongoc_client_pool_pop");
587+
/* @todo Since 2017 this requirement has been documented but not actually enforced. For now we are leaving it
588+
* unenforced, for backward compatibility. This usage remains unsafe and incorrect. When possible, this should be
589+
* modified to return false without modifying the APM callbacks. */
590+
mongoc_log_and_monitor_instance_set_apm_callbacks (&pool->topology->log_and_monitor, callbacks, context);
591+
pool->apm_callbacks_set = true;
592+
return true;
590593

591-
// Update callbacks on the pool
592-
if (callbacks) {
593-
pool->apm_callbacks = *callbacks;
594594
} else {
595-
pool->apm_callbacks = (mongoc_apm_callbacks_t){0};
595+
// Now we can be sure no other threads are relying on concurrent access to the instance yet.
596+
mongoc_log_and_monitor_instance_set_apm_callbacks (&pool->topology->log_and_monitor, callbacks, context);
597+
pool->apm_callbacks_set = true;
598+
return true;
596599
}
597-
pool->apm_context = context;
598-
599-
// Update callbacks on the topology
600-
mongoc_topology_set_apm_callbacks (topology, tdmod.new_td, callbacks, context);
601-
602-
// Signal that we have already set the callbacks
603-
pool->apm_callbacks_set = true;
604-
605-
// Save our updated topology
606-
mc_tpld_modify_commit (tdmod);
607-
608-
return true;
609600
}
610601

611602
bool
@@ -618,14 +609,14 @@ mongoc_client_pool_set_structured_log_opts (mongoc_client_pool_t *pool, const mo
618609
* and only before the first client is initialized. Structured logging is generally
619610
* expected to warn but not quit when encountering initialization errors. */
620611
if (pool->structured_log_opts_set) {
621-
MONGOC_WARNING ("mongoc_client_pool_set_structured_log_opts can only be called once per pool");
612+
MONGOC_ERROR ("mongoc_client_pool_set_structured_log_opts can only be called once per pool");
622613
return false;
623614
} else if (pool->client_initialized) {
624-
MONGOC_WARNING ("mongoc_client_pool_set_structured_log_opts can only be called before mongoc_client_pool_pop");
615+
MONGOC_ERROR ("mongoc_client_pool_set_structured_log_opts can only be called before mongoc_client_pool_pop");
625616
return false;
626617
} else {
627618
// Now we can be sure no other threads are relying on concurrent access to the instance yet.
628-
mongoc_topology_set_structured_log_opts (pool->topology, opts);
619+
mongoc_log_and_monitor_instance_set_structured_log_opts (&pool->topology->log_and_monitor, opts);
629620
pool->structured_log_opts_set = true;
630621
return true;
631622
}

src/libmongoc/src/mongoc/mongoc-client-private.h

-6
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,6 @@ struct _mongoc_client_t {
107107
mongoc_read_concern_t *read_concern;
108108
mongoc_write_concern_t *write_concern;
109109

110-
mongoc_apm_callbacks_t apm_callbacks;
111-
void *apm_context;
112-
113110
int32_t error_api_version;
114111
bool error_api_set;
115112

@@ -151,9 +148,6 @@ _mongoc_client_get_rr (const char *hostname,
151148
mongoc_client_t *
152149
_mongoc_client_new_from_topology (mongoc_topology_t *topology);
153150

154-
bool
155-
_mongoc_client_set_apm_callbacks_private (mongoc_client_t *client, mongoc_apm_callbacks_t *callbacks, void *context);
156-
157151
mongoc_stream_t *
158152
mongoc_client_default_stream_initiator (const mongoc_uri_t *uri,
159153
const mongoc_host_list_t *host,

src/libmongoc/src/mongoc/mongoc-client.c

+27-49
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,7 @@ _mongoc_client_new_from_topology (mongoc_topology_t *topology)
11221122
}
11231123
#endif
11241124

1125-
mongoc_structured_log (topology->structured_log,
1125+
mongoc_structured_log (topology->log_and_monitor.structured_log,
11261126
MONGOC_STRUCTURED_LOG_LEVEL_DEBUG,
11271127
MONGOC_STRUCTURED_LOG_COMPONENT_CONNECTION,
11281128
"Client created");
@@ -1646,8 +1646,6 @@ _mongoc_client_retryable_read_command_with_stream (mongoc_client_t *client,
16461646
* server does not support retryable reads, fall through and allow the
16471647
* original error to be reported. */
16481648
if (is_retryable && _mongoc_read_error_get_type (ret, error, reply) == MONGOC_READ_ERR_RETRY) {
1649-
bson_error_t ignored_error;
1650-
16511649
/* each read command may be retried at most once */
16521650
is_retryable = false;
16531651

@@ -1667,8 +1665,13 @@ _mongoc_client_retryable_read_command_with_stream (mongoc_client_t *client,
16671665
.has_operation_id = true,
16681666
.operation_id = parts->assembled.operation_id,
16691667
};
1670-
retry_server_stream = mongoc_cluster_stream_for_reads (
1671-
&client->cluster, &ss_log_context, parts->read_prefs, parts->assembled.session, ds, NULL, &ignored_error);
1668+
retry_server_stream = mongoc_cluster_stream_for_reads (&client->cluster,
1669+
&ss_log_context,
1670+
parts->read_prefs,
1671+
parts->assembled.session,
1672+
ds,
1673+
NULL /* reply */,
1674+
NULL /* error */);
16721675

16731676
mongoc_deprioritized_servers_destroy (ds);
16741677
}
@@ -2165,14 +2168,14 @@ _mongoc_client_monitor_op_killcursors (mongoc_cluster_t *cluster,
21652168
const char *collection)
21662169
{
21672170
bson_t doc;
2168-
mongoc_client_t *client;
21692171
mongoc_apm_command_started_t event;
21702172

21712173
ENTRY;
21722174

2173-
client = cluster->client;
2175+
mongoc_client_t *client = cluster->client;
2176+
const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor;
21742177

2175-
if (!client->apm_callbacks.started) {
2178+
if (!log_and_monitor->apm_callbacks.started) {
21762179
return;
21772180
}
21782181

@@ -2189,9 +2192,9 @@ _mongoc_client_monitor_op_killcursors (mongoc_cluster_t *cluster,
21892192
&server_stream->sd->service_id,
21902193
server_stream->sd->server_connection_id,
21912194
NULL,
2192-
client->apm_context);
2195+
log_and_monitor->apm_context);
21932196

2194-
client->apm_callbacks.started (&event);
2197+
log_and_monitor->apm_callbacks.started (&event);
21952198
mongoc_apm_command_started_cleanup (&event);
21962199
bson_destroy (&doc);
21972200

@@ -2207,16 +2210,16 @@ _mongoc_client_monitor_op_killcursors_succeeded (mongoc_cluster_t *cluster,
22072210
int64_t operation_id,
22082211
const char *db)
22092212
{
2210-
mongoc_client_t *client;
22112213
bson_t doc;
22122214
bson_array_builder_t *cursors_unknown;
22132215
mongoc_apm_command_succeeded_t event;
22142216

22152217
ENTRY;
22162218

2217-
client = cluster->client;
2219+
mongoc_client_t *client = cluster->client;
2220+
const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor;
22182221

2219-
if (!client->apm_callbacks.succeeded) {
2222+
if (!log_and_monitor->apm_callbacks.succeeded) {
22202223
EXIT;
22212224
}
22222225

@@ -2239,9 +2242,9 @@ _mongoc_client_monitor_op_killcursors_succeeded (mongoc_cluster_t *cluster,
22392242
&server_stream->sd->service_id,
22402243
server_stream->sd->server_connection_id,
22412244
false,
2242-
client->apm_context);
2245+
log_and_monitor->apm_context);
22432246

2244-
client->apm_callbacks.succeeded (&event);
2247+
log_and_monitor->apm_callbacks.succeeded (&event);
22452248

22462249
mongoc_apm_command_succeeded_cleanup (&event);
22472250
bson_destroy (&doc);
@@ -2256,15 +2259,15 @@ _mongoc_client_monitor_op_killcursors_failed (mongoc_cluster_t *cluster,
22562259
int64_t operation_id,
22572260
const char *db)
22582261
{
2259-
mongoc_client_t *client;
22602262
bson_t doc;
22612263
mongoc_apm_command_failed_t event;
22622264

22632265
ENTRY;
22642266

2265-
client = cluster->client;
2267+
mongoc_client_t *client = cluster->client;
2268+
const mongoc_log_and_monitor_instance_t *log_and_monitor = &client->topology->log_and_monitor;
22662269

2267-
if (!client->apm_callbacks.failed) {
2270+
if (!log_and_monitor->apm_callbacks.failed) {
22682271
EXIT;
22692272
}
22702273

@@ -2285,9 +2288,9 @@ _mongoc_client_monitor_op_killcursors_failed (mongoc_cluster_t *cluster,
22852288
&server_stream->sd->service_id,
22862289
server_stream->sd->server_connection_id,
22872290
false,
2288-
client->apm_context);
2291+
log_and_monitor->apm_context);
22892292

2290-
client->apm_callbacks.failed (&event);
2293+
log_and_monitor->apm_callbacks.failed (&event);
22912294

22922295
mongoc_apm_command_failed_cleanup (&event);
22932296
bson_destroy (&doc);
@@ -2576,33 +2579,6 @@ mongoc_client_set_stream_initiator (mongoc_client_t *client, mongoc_stream_initi
25762579
}
25772580

25782581

2579-
bool
2580-
_mongoc_client_set_apm_callbacks_private (mongoc_client_t *client, mongoc_apm_callbacks_t *callbacks, void *context)
2581-
{
2582-
BSON_ASSERT_PARAM (client);
2583-
2584-
if (callbacks) {
2585-
memcpy (&client->apm_callbacks, callbacks, sizeof (mongoc_apm_callbacks_t));
2586-
} else {
2587-
memset (&client->apm_callbacks, 0, sizeof (mongoc_apm_callbacks_t));
2588-
}
2589-
2590-
client->apm_context = context;
2591-
2592-
/* A client pool sets APM callbacks for the entire pool. */
2593-
if (client->topology->single_threaded) {
2594-
mongoc_topology_set_apm_callbacks (client->topology,
2595-
/* We are safe to modify the shared_descr directly, since we are
2596-
* single-threaded */
2597-
mc_tpld_unsafe_get_mutable (client->topology),
2598-
callbacks,
2599-
context);
2600-
}
2601-
2602-
return true;
2603-
}
2604-
2605-
26062582
bool
26072583
mongoc_client_set_apm_callbacks (mongoc_client_t *client, mongoc_apm_callbacks_t *callbacks, void *context)
26082584
{
@@ -2614,7 +2590,9 @@ mongoc_client_set_apm_callbacks (mongoc_client_t *client, mongoc_apm_callbacks_t
26142590
return false;
26152591
}
26162592

2617-
return _mongoc_client_set_apm_callbacks_private (client, callbacks, context);
2593+
mongoc_log_and_monitor_instance_set_apm_callbacks (&client->topology->log_and_monitor, callbacks, context);
2594+
2595+
return true;
26182596
}
26192597

26202598

@@ -2625,7 +2603,7 @@ mongoc_client_set_structured_log_opts (mongoc_client_t *client, const mongoc_str
26252603
BSON_OPTIONAL_PARAM (opts);
26262604

26272605
if (client->topology->single_threaded) {
2628-
mongoc_topology_set_structured_log_opts (client->topology, opts);
2606+
mongoc_log_and_monitor_instance_set_structured_log_opts (&client->topology->log_and_monitor, opts);
26292607
return true;
26302608
} else {
26312609
MONGOC_WARNING ("Cannot set structured log options on a pooled client, use "

0 commit comments

Comments
 (0)