summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Buerger <will.buerger@mongodb.com>2023-05-05 13:36:36 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-05-05 16:42:44 +0000
commit72e24ba9bbc1c3043d35d47e30cda75075ff3d95 (patch)
tree4673ecbe265e23f3a01cac1e187c0290c71110a3
parentd66daf618a9005eaba4a8c9fa3746ef27ab80427 (diff)
downloadmongo-72e24ba9bbc1c3043d35d47e30cda75075ff3d95.tar.gz
SERVER-76557: Keep RequestShapifiers in telemetry store
-rw-r--r--src/mongo/db/clientcursor.cpp9
-rw-r--r--src/mongo/db/clientcursor.h7
-rw-r--r--src/mongo/db/commands/find_cmd.cpp10
-rw-r--r--src/mongo/db/commands/run_aggregate.cpp2
-rw-r--r--src/mongo/db/curop.h4
-rw-r--r--src/mongo/db/pipeline/SConscript2
-rw-r--r--src/mongo/db/pipeline/aggregate_request_shapifier.cpp13
-rw-r--r--src/mongo/db/pipeline/aggregate_request_shapifier.h2
-rw-r--r--src/mongo/db/pipeline/document_source_telemetry.cpp4
-rw-r--r--src/mongo/db/query/SConscript2
-rw-r--r--src/mongo/db/query/find.cpp2
-rw-r--r--src/mongo/db/query/find_request_shapifier.cpp13
-rw-r--r--src/mongo/db/query/find_request_shapifier.h15
-rw-r--r--src/mongo/db/query/request_shapifier.h10
-rw-r--r--src/mongo/db/query/telemetry.cpp78
-rw-r--r--src/mongo/db/query/telemetry.h55
-rw-r--r--src/mongo/db/query/telemetry_store_test.cpp135
-rw-r--r--src/mongo/s/commands/cluster_find_cmd.h10
-rw-r--r--src/mongo/s/query/cluster_aggregation_planner.cpp2
-rw-r--r--src/mongo/s/query/cluster_client_cursor.h6
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl.cpp9
-rw-r--r--src/mongo/s/query/cluster_client_cursor_impl.h5
-rw-r--r--src/mongo/s/query/cluster_client_cursor_mock.cpp4
-rw-r--r--src/mongo/s/query/cluster_client_cursor_mock.h3
-rw-r--r--src/mongo/s/query/cluster_cursor_manager.cpp5
-rw-r--r--src/mongo/s/query/cluster_cursor_manager.h3
-rw-r--r--src/mongo/s/query/cluster_find.cpp2
-rw-r--r--src/mongo/s/query/store_possible_cursor.cpp2
28 files changed, 219 insertions, 195 deletions
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index 9037096354b..a18b2fec45b 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -125,6 +125,8 @@ ClientCursor::ClientCursor(ClientCursorParams params,
_planCacheKey(CurOp::get(operationUsingCursor)->debug().planCacheKey),
_queryHash(CurOp::get(operationUsingCursor)->debug().queryHash),
_telemetryStoreKey(CurOp::get(operationUsingCursor)->debug().telemetryStoreKey),
+ _telemetryRequestShapifier(
+ std::move(CurOp::get(operationUsingCursor)->debug().telemetryRequestShapifier)),
_shouldOmitDiagnosticInformation(
CurOp::get(operationUsingCursor)->debug().shouldOmitDiagnosticInformation),
_opKey(operationUsingCursor->getOperationKey()) {
@@ -161,7 +163,7 @@ void ClientCursor::dispose(OperationContext* opCtx, boost::optional<Date_t> now)
if (_telemetryStoreKey && opCtx) {
telemetry::writeTelemetry(opCtx,
_telemetryStoreKey,
- getOriginatingCommandObj(),
+ std::move(_telemetryRequestShapifier),
_metrics.executionTime.value_or(Microseconds{0}).count(),
_metrics.nreturned.value_or(0));
}
@@ -397,14 +399,15 @@ void collectTelemetryMongod(OperationContext* opCtx, ClientCursorPin& pinnedCurs
pinnedCursor->incrementCursorMetrics(CurOp::get(opCtx)->debug().additiveMetrics);
}
-void collectTelemetryMongod(OperationContext* opCtx, const BSONObj& originatingCommand) {
+void collectTelemetryMongod(OperationContext* opCtx,
+ std::unique_ptr<telemetry::RequestShapifier> requestShapifier) {
// If we haven't registered a cursor to prepare for getMore requests, we record
// telemetry directly.
auto& opDebug = CurOp::get(opCtx)->debug();
telemetry::writeTelemetry(
opCtx,
opDebug.telemetryStoreKey,
- originatingCommand,
+ std::move(requestShapifier),
opDebug.additiveMetrics.executionTime.value_or(Microseconds{0}).count(),
opDebug.additiveMetrics.nreturned.value_or(0));
}
diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h
index e254f112bce..68c0a48e260 100644
--- a/src/mongo/db/clientcursor.h
+++ b/src/mongo/db/clientcursor.h
@@ -453,6 +453,9 @@ private:
// Metrics that are accumulated over the lifetime of the cursor, incremented with each getMore.
// Useful for diagnostics like telemetry.
OpDebug::AdditiveMetrics _metrics;
+ // The RequestShapifier used by telemetry to shapify the request payload into the telemetry
+ // store key.
+ std::unique_ptr<telemetry::RequestShapifier> _telemetryRequestShapifier;
// Flag to decide if diagnostic information should be omitted.
bool _shouldOmitDiagnosticInformation{false};
@@ -595,6 +598,6 @@ void startClientCursorMonitor();
* getMore requests), so these should only be called from those request paths.
*/
void collectTelemetryMongod(OperationContext* opCtx, ClientCursorPin& cursor);
-void collectTelemetryMongod(OperationContext* opCtx, const BSONObj& originatingCommand);
-
+void collectTelemetryMongod(OperationContext* opCtx,
+ std::unique_ptr<telemetry::RequestShapifier> requestShapifier);
} // namespace mongo
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index add8ceb3d57..2b6d5cb9dc8 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -563,11 +563,11 @@ public:
if (collection) {
// Collect telemetry. Exclude queries against collections with encrypted fields.
if (!collection.get()->getCollectionOptions().encryptedFieldConfig) {
- telemetry::registerRequest(
- telemetry::FindRequestShapifier(cq->getFindCommandRequest(), opCtx),
- collection.get()->ns(),
- opCtx,
- cq->getExpCtx());
+ telemetry::registerRequest(std::make_unique<telemetry::FindRequestShapifier>(
+ cq->getFindCommandRequest(), opCtx),
+ collection.get()->ns(),
+ opCtx,
+ cq->getExpCtx());
}
}
diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp
index 4b2c535cbc7..8a2d675982d 100644
--- a/src/mongo/db/commands/run_aggregate.cpp
+++ b/src/mongo/db/commands/run_aggregate.cpp
@@ -1226,7 +1226,7 @@ Status runAggregate(OperationContext* opCtx,
if (keepCursor) {
collectTelemetryMongod(opCtx, pins[0]);
} else {
- collectTelemetryMongod(opCtx, cmdObj);
+ collectTelemetryMongod(opCtx, std::move(curOp->debug().telemetryRequestShapifier));
}
// For an optimized away pipeline, signal the cache that a query operation has completed.
diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h
index e934afe9f68..83fa93a576b 100644
--- a/src/mongo/db/curop.h
+++ b/src/mongo/db/curop.h
@@ -40,6 +40,7 @@
#include "mongo/db/cursor_id.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/profile_filter.h"
+#include "mongo/db/query/request_shapifier.h"
#include "mongo/db/server_options.h"
#include "mongo/db/stats/resource_consumption_metrics.h"
#include "mongo/db/write_concern_options.h"
@@ -294,6 +295,9 @@ public:
// The shape of the original query serialized with readConcern, application name, and namespace.
// If boost::none, telemetry should not be collected for this operation.
boost::optional<BSONObj> telemetryStoreKey;
+ // The RequestShapifier used by telemetry to shapify the request payload into the telemetry
+ // store key.
+ std::unique_ptr<telemetry::RequestShapifier> telemetryRequestShapifier;
// The query framework that this operation used. Will be unknown for non query operations.
PlanExecutor::QueryFramework queryFramework{PlanExecutor::QueryFramework::kUnknown};
diff --git a/src/mongo/db/pipeline/SConscript b/src/mongo/db/pipeline/SConscript
index cac6cac809e..b620f3a4ac3 100644
--- a/src/mongo/db/pipeline/SConscript
+++ b/src/mongo/db/pipeline/SConscript
@@ -272,7 +272,7 @@ pipelineEnv.Library(
target='pipeline',
source=[
'accumulator_internal_construct_stats.cpp',
- # TODO SERVER-76557 move into new query_shape target
+ # TODO SERVER-73152 move into new query_shape target
'aggregate_request_shapifier.cpp',
'document_source.cpp',
'document_source_add_fields.cpp',
diff --git a/src/mongo/db/pipeline/aggregate_request_shapifier.cpp b/src/mongo/db/pipeline/aggregate_request_shapifier.cpp
index 74d9214cd65..40ed6c2ce79 100644
--- a/src/mongo/db/pipeline/aggregate_request_shapifier.cpp
+++ b/src/mongo/db/pipeline/aggregate_request_shapifier.cpp
@@ -33,11 +33,22 @@
namespace mongo::telemetry {
+BSONObj AggregateRequestShapifier::makeTelemetryKey(const SerializationOptions& opts,
+ OperationContext* opCtx) const {
+ // TODO SERVER-76087 We will likely want to set a flag here to stop $search from calling out
+ // to mongot.
+ auto expCtx = make_intrusive<ExpressionContext>(opCtx, nullptr, _request.getNamespace());
+ expCtx->variables.setDefaultRuntimeConstants(opCtx);
+ expCtx->maxFeatureCompatibilityVersion = boost::none; // Ensure all features are allowed.
+ expCtx->stopExpressionCounters();
+ return makeTelemetryKey(opts, expCtx);
+}
+
BSONObj AggregateRequestShapifier::makeTelemetryKey(
const SerializationOptions& opts, const boost::intrusive_ptr<ExpressionContext>& expCtx) const {
BSONObjBuilder bob;
- // TODO SERVER-76557 move actually pipeline serialization into query_shape
+ // TODO SERVER-73152 move pipeline serialization into query_shape::extractQueryShape
auto serializedPipeline = _pipeline.serializeToBson(opts);
bob.append("queryShape",
query_shape::extractQueryShape(_request, serializedPipeline, opts, expCtx));
diff --git a/src/mongo/db/pipeline/aggregate_request_shapifier.h b/src/mongo/db/pipeline/aggregate_request_shapifier.h
index 91cfbf604a1..3a0c41f8dd9 100644
--- a/src/mongo/db/pipeline/aggregate_request_shapifier.h
+++ b/src/mongo/db/pipeline/aggregate_request_shapifier.h
@@ -50,6 +50,8 @@ public:
virtual ~AggregateRequestShapifier() = default;
+ BSONObj makeTelemetryKey(const SerializationOptions& opts, OperationContext* opCtx) const final;
+
BSONObj makeTelemetryKey(const SerializationOptions& opts,
const boost::intrusive_ptr<ExpressionContext>& expCtx) const final;
diff --git a/src/mongo/db/pipeline/document_source_telemetry.cpp b/src/mongo/db/pipeline/document_source_telemetry.cpp
index 01f35893bac..ad1ce6cea2a 100644
--- a/src/mongo/db/pipeline/document_source_telemetry.cpp
+++ b/src/mongo/db/pipeline/document_source_telemetry.cpp
@@ -190,8 +190,8 @@ DocumentSource::GetNextResult DocumentSourceTelemetry::doGetNext() {
Timestamp{Timestamp(Date_t::now().toMillisSinceEpoch() / 1000, 0)};
for (auto&& [key, metrics] : *partition) {
try {
- auto hmacKey =
- metrics->applyHmacToKey(key, _applyHmacToIdentifiers, _hmacKey, pExpCtx->opCtx);
+ auto hmacKey = metrics->makeTelemetryKey(
+ key, _applyHmacToIdentifiers, _hmacKey, pExpCtx->opCtx);
_materializedPartition.push_back({{"key", std::move(hmacKey)},
{"metrics", metrics->toBSON()},
{"asOf", partitionReadTime}});
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index af5075b020f..22e24674e1d 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -138,7 +138,7 @@ env.Library(
"explain_common.cpp",
"find_common.cpp",
"parsed_distinct.cpp",
- # TODO SERVER-76557 move into new query_shape target
+ # TODO SERVER-73152 move into new query_shape target
"find_request_shapifier.cpp",
],
LIBDEPS=[
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index aab6684e772..c54138afd4b 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -127,7 +127,7 @@ void endQueryOp(OperationContext* opCtx,
if (cursor) {
collectTelemetryMongod(opCtx, *cursor);
} else {
- collectTelemetryMongod(opCtx, cmdObj);
+ collectTelemetryMongod(opCtx, std::move(curOp->debug().telemetryRequestShapifier));
}
if (collection) {
diff --git a/src/mongo/db/query/find_request_shapifier.cpp b/src/mongo/db/query/find_request_shapifier.cpp
index ae76951562a..f8794683fbd 100644
--- a/src/mongo/db/query/find_request_shapifier.cpp
+++ b/src/mongo/db/query/find_request_shapifier.cpp
@@ -35,13 +35,24 @@
#include "mongo/db/query/query_shape.h"
namespace mongo::telemetry {
+BSONObj FindRequestShapifier::makeTelemetryKey(const SerializationOptions& opts,
+ OperationContext* opCtx) const {
+ auto expCtx = make_intrusive<ExpressionContext>(
+ opCtx, _request, nullptr /* collator doesn't matter here.*/, false /* mayDbProfile */);
+ expCtx->maxFeatureCompatibilityVersion = boost::none; // Ensure all features are allowed.
+ // Expression counters are reported in serverStatus to indicate how often clients use certain
+ // expressions/stages, so it's a side effect tied to parsing. We must stop expression counters
+ // before re-parsing to avoid adding to the counters more than once per a given query.
+ expCtx->stopExpressionCounters();
+ return makeTelemetryKey(opts, expCtx);
+}
+
BSONObj FindRequestShapifier::makeTelemetryKey(
const SerializationOptions& opts, const boost::intrusive_ptr<ExpressionContext>& expCtx) const {
BSONObjBuilder bob;
bob.append("queryShape", query_shape::extractQueryShape(_request, opts, expCtx));
-
if (auto optObj = _request.getReadConcern()) {
// Read concern should not be considered a literal.
bob.append(FindCommandRequest::kReadConcernFieldName, optObj.get());
diff --git a/src/mongo/db/query/find_request_shapifier.h b/src/mongo/db/query/find_request_shapifier.h
index 2885a2cd025..b03f84eb1ab 100644
--- a/src/mongo/db/query/find_request_shapifier.h
+++ b/src/mongo/db/query/find_request_shapifier.h
@@ -39,17 +39,22 @@ namespace mongo::telemetry {
*/
class FindRequestShapifier final : public RequestShapifier {
public:
- FindRequestShapifier(const FindCommandRequest& request,
- OperationContext* opCtx,
- const boost::optional<std::string> applicationName = boost::none)
- : RequestShapifier(opCtx, applicationName), _request(request) {}
+ FindRequestShapifier(
+ FindCommandRequest request, // We pass FindCommandRequest by value in order to make a copy
+ // since this instance may outlive the original request once
+ // the RequestShapifier is moved to the telemetry store.
+ OperationContext* opCtx,
+ const boost::optional<std::string> applicationName = boost::none)
+ : RequestShapifier(opCtx, applicationName), _request(std::move(request)) {}
virtual ~FindRequestShapifier() = default;
+ BSONObj makeTelemetryKey(const SerializationOptions& opts, OperationContext* opCtx) const final;
+
BSONObj makeTelemetryKey(const SerializationOptions& opts,
const boost::intrusive_ptr<ExpressionContext>& expCtx) const final;
private:
- const FindCommandRequest& _request;
+ FindCommandRequest _request;
};
} // namespace mongo::telemetry
diff --git a/src/mongo/db/query/request_shapifier.h b/src/mongo/db/query/request_shapifier.h
index 2d12ede90d7..6f3d79f61be 100644
--- a/src/mongo/db/query/request_shapifier.h
+++ b/src/mongo/db/query/request_shapifier.h
@@ -44,6 +44,16 @@ namespace mongo::telemetry {
class RequestShapifier {
public:
virtual ~RequestShapifier() = default;
+
+ /**
+ * makeTelemetryKey generates the telemetry key representative of the specific request's
+ * payload. If there exists an ExpressionContext set up to parse and evaluate the request,
+ * makeTelemetryKey should be called with that ExpressionContext. If not, you can call the
+ * overload that accepts the OperationContext and will construct a minimally-acceptable
+ * ExpressionContext for the sake of generating the key.
+ */
+ virtual BSONObj makeTelemetryKey(const SerializationOptions& opts,
+ OperationContext* opCtx) const = 0;
virtual BSONObj makeTelemetryKey(
const SerializationOptions& opts,
const boost::intrusive_ptr<ExpressionContext>& expCtx) const = 0;
diff --git a/src/mongo/db/query/telemetry.cpp b/src/mongo/db/query/telemetry.cpp
index 023573910cf..766d2a1f131 100644
--- a/src/mongo/db/query/telemetry.cpp
+++ b/src/mongo/db/query/telemetry.cpp
@@ -39,8 +39,6 @@
#include "mongo/db/pipeline/aggregate_command_gen.h"
#include "mongo/db/pipeline/process_interface/stub_mongo_process_interface.h"
#include "mongo/db/query/find_command_gen.h"
-// TODO SERVER-76557 remove include of find_request_shapifier
-#include "mongo/db/query/find_request_shapifier.h"
#include "mongo/db/query/plan_explainer.h"
#include "mongo/db/query/projection_ast_util.h"
#include "mongo/db/query/projection_parser.h"
@@ -79,36 +77,6 @@ boost::optional<std::string> getApplicationName(const OperationContext* opCtx) {
}
} // namespace
-// TODO SERVER-76557 can remove this makeTelemetryKey
-BSONObj makeTelemetryKey(const FindCommandRequest& findCommand,
- const SerializationOptions& opts,
- const boost::intrusive_ptr<ExpressionContext>& expCtx,
- boost::optional<const TelemetryMetrics&> existingMetrics) {
-
- BSONObjBuilder bob;
- bob.append("queryShape", query_shape::extractQueryShape(findCommand, opts, expCtx));
- if (auto optObj = findCommand.getReadConcern()) {
- // Read concern should not be considered a literal.
- bob.append(FindCommandRequest::kReadConcernFieldName, optObj.get());
- }
- auto appName = [&]() -> boost::optional<std::string> {
- if (existingMetrics.has_value()) {
- if (existingMetrics->applicationName.has_value()) {
- return existingMetrics->applicationName;
- }
- } else {
- if (auto appName = getApplicationName(expCtx->opCtx)) {
- return appName.value();
- }
- }
- return boost::none;
- }();
- if (appName.has_value()) {
- bob.append("applicationName", opts.serializeIdentifier(appName.value()));
- }
- return bob.obj();
-}
-
CounterMetric telemetryStoreSizeEstimateBytesMetric("telemetry.telemetryStoreSizeEstimateBytes");
namespace {
@@ -234,7 +202,7 @@ ServiceContext::ConstructorActionRegisterer telemetryStoreManagerRegisterer{
// That is, the number of cpu cores.
size_t numPartitions = ProcessInfo::getNumCores();
size_t partitionBytes = size / numPartitions;
- size_t metricsSize = sizeof(TelemetryMetrics);
+ size_t metricsSize = sizeof(TelemetryEntry);
if (partitionBytes < metricsSize * 10) {
numPartitions = size / metricsSize;
if (numPartitions < 1) {
@@ -319,7 +287,7 @@ void throwIfEncounteringFLEPayload(const BSONElement& e) {
/**
* Upon reading telemetry data, we apply hmac to some keys. This is the list. See
- * TelemetryMetrics::applyHmacToKey().
+ * TelemetryEntry::makeTelemetryKey().
*/
const stdx::unordered_set<std::string> kKeysToApplyHmac = {"pipeline", "find"};
@@ -371,7 +339,7 @@ static const StringData replacementForLiteralArgs = "?"_sd;
} // namespace
-BSONObj TelemetryMetrics::applyHmacToKey(const BSONObj& key,
+BSONObj TelemetryEntry::makeTelemetryKey(const BSONObj& key,
bool applyHmacToIdentifiers,
std::string hmacKey,
OperationContext* opCtx) const {
@@ -394,37 +362,20 @@ BSONObj TelemetryMetrics::applyHmacToKey(const BSONObj& key,
// }
// queryShape may include additional fields, eg hint, limit sort, etc, depending on the original
// query.
- if (cmdObj.hasField(FindCommandRequest::kCommandName)) {
- tassert(7198600, "Find command must have a namespace string.", this->nss.nss().has_value());
- auto findCommand =
- query_request_helper::makeFromFindCommand(cmdObj, this->nss.nss().value(), false);
- auto nss = findCommand->getNamespaceOrUUID().nss();
- uassert(7349400, "Namespace must be defined", nss.has_value());
+ // TODO SERVER-73152 incorporate aggregation request into same path so that nullptr check is
+ // unnecessary
+ if (requestShapifier != nullptr) {
auto serializationOpts = applyHmacToIdentifiers
? SerializationOptions(
[&](StringData sd) { return sha256HmacStringDataHasher(hmacKey, sd); },
LiteralSerializationPolicy::kToDebugTypeString)
: SerializationOptions(false);
- auto expCtx = make_intrusive<ExpressionContext>(opCtx,
- *findCommand,
- nullptr /* collator doesn't matter here.*/,
- false /* mayDbProfile */);
- expCtx->maxFeatureCompatibilityVersion = boost::none; // Ensure all features are allowed.
- expCtx->stopExpressionCounters();
-
- // TODO SERVER-76557 call makeTelemetryKey thru FindRequestShapifier kept in telemetry store
- auto key = makeTelemetryKey(*findCommand, serializationOpts, expCtx, *this);
- // TODO: SERVER-75512 as part of this ticket, no form of the key (hmac applied or not) will
- // be cached with TelemetryMetrics.
- if (applyHmacToIdentifiers) {
- _hmacAppliedKey = key;
- return *_hmacAppliedKey;
- }
- return key;
+ return requestShapifier->makeTelemetryKey(serializationOpts, opCtx);
}
+ // TODO SERVER-73152 remove all special aggregation logic below
// The telemetry key for agg queries is of the following form:
// { "agg": {...}, "namespace": "...", "applicationName": "...", ... }
//
@@ -521,7 +472,7 @@ void registerAggRequest(const AggregateCommandRequest& request, OperationContext
CurOp::get(opCtx)->debug().telemetryStoreKey = telemetryKey.obj();
}
-void registerRequest(const RequestShapifier& requestShapifier,
+void registerRequest(std::unique_ptr<RequestShapifier> requestShapifier,
const NamespaceString& collection,
OperationContext* opCtx,
const boost::intrusive_ptr<ExpressionContext>& expCtx) {
@@ -542,7 +493,8 @@ void registerRequest(const RequestShapifier& requestShapifier,
options.literalPolicy = LiteralSerializationPolicy::kToDebugTypeString;
options.replacementForLiteralArgs = replacementForLiteralArgs;
CurOp::get(opCtx)->debug().telemetryStoreKey =
- requestShapifier.makeTelemetryKey(options, expCtx);
+ requestShapifier->makeTelemetryKey(options, expCtx);
+ CurOp::get(opCtx)->debug().telemetryRequestShapifier = std::move(requestShapifier);
}
TelemetryStore& getTelemetryStore(OperationContext* opCtx) {
@@ -555,7 +507,7 @@ TelemetryStore& getTelemetryStore(OperationContext* opCtx) {
void writeTelemetry(OperationContext* opCtx,
boost::optional<BSONObj> telemetryKey,
- const BSONObj& cmdObj,
+ std::unique_ptr<RequestShapifier> requestShapifier,
const uint64_t queryExecMicros,
const uint64_t docsReturned) {
if (!telemetryKey) {
@@ -563,14 +515,14 @@ void writeTelemetry(OperationContext* opCtx,
}
auto&& telemetryStore = getTelemetryStore(opCtx);
auto&& [statusWithMetrics, partitionLock] = telemetryStore.getWithPartitionLock(*telemetryKey);
- std::shared_ptr<TelemetryMetrics> metrics;
+ std::shared_ptr<TelemetryEntry> metrics;
if (statusWithMetrics.isOK()) {
metrics = *statusWithMetrics.getValue();
} else {
size_t numEvicted =
telemetryStore.put(*telemetryKey,
- std::make_shared<TelemetryMetrics>(
- cmdObj, getApplicationName(opCtx), CurOp::get(opCtx)->getNSS()),
+ std::make_shared<TelemetryEntry>(std::move(requestShapifier),
+ CurOp::get(opCtx)->getNSS()),
partitionLock);
telemetryEvictedMetric.increment(numEvicted);
auto newMetrics = partitionLock->get(*telemetryKey);
diff --git a/src/mongo/db/query/telemetry.h b/src/mongo/db/query/telemetry.h
index b49e70762c7..9d2fdaa7b5b 100644
--- a/src/mongo/db/query/telemetry.h
+++ b/src/mongo/db/query/telemetry.h
@@ -97,26 +97,21 @@ struct AggregatedMetric {
extern CounterMetric telemetryStoreSizeEstimateBytesMetric;
// Used to aggregate the metrics for one telemetry key over all its executions.
-class TelemetryMetrics {
+class TelemetryEntry {
public:
- TelemetryMetrics(const BSONObj& cmdObj,
- boost::optional<std::string> applicationName,
- NamespaceStringOrUUID nss)
+ TelemetryEntry(std::unique_ptr<RequestShapifier> requestShapifier, NamespaceStringOrUUID nss)
: firstSeenTimestamp(Date_t::now().toMillisSinceEpoch() / 1000, 0),
- cmdObj(cmdObj.copy()),
- applicationName(applicationName),
+ requestShapifier(std::move(requestShapifier)),
nss(nss) {
- telemetryStoreSizeEstimateBytesMetric.increment(sizeof(TelemetryMetrics) + sizeof(BSONObj) +
- cmdObj.objsize());
+ telemetryStoreSizeEstimateBytesMetric.increment(sizeof(TelemetryEntry) + sizeof(BSONObj));
}
- ~TelemetryMetrics() {
- telemetryStoreSizeEstimateBytesMetric.decrement(sizeof(TelemetryMetrics) + sizeof(BSONObj) +
- cmdObj.objsize());
+ ~TelemetryEntry() {
+ telemetryStoreSizeEstimateBytesMetric.decrement(sizeof(TelemetryEntry) + sizeof(BSONObj));
}
BSONObj toBSON() const {
- BSONObjBuilder builder{sizeof(TelemetryMetrics) + 100};
+ BSONObjBuilder builder{sizeof(TelemetryEntry) + 100};
builder.append("lastExecutionMicros", (BSONNumeric)lastExecutionMicros);
builder.append("execCount", (BSONNumeric)execCount);
queryExecMicros.appendTo(builder, "queryExecMicros");
@@ -128,10 +123,10 @@ public:
/**
* Redact a given telemetry key and set _keySize.
*/
- BSONObj applyHmacToKey(const BSONObj& key,
- bool applyHmacToIdentifiers,
- std::string hmacKey,
- OperationContext* opCtx) const;
+ BSONObj makeTelemetryKey(const BSONObj& key,
+ bool applyHmacToIdentifiers,
+ std::string hmacKey,
+ OperationContext* opCtx) const;
/**
* Timestamp for when this query shape was added to the store. Set on construction.
@@ -152,17 +147,7 @@ public:
AggregatedMetric docsReturned;
- /**
- * A representative command for a given telemetry key. This is used to derive the hmac applied
- * telemetry key at read-time.
- */
- BSONObj cmdObj;
-
- /**
- * The application name that is a part of the query shape. It is necessary to store this
- * separately from the telemetry key since it exists on the OpCtx, not the cmdObj.
- */
- boost::optional<std::string> applicationName;
+ std::unique_ptr<RequestShapifier> requestShapifier;
NamespaceStringOrUUID nss;
@@ -181,16 +166,16 @@ struct TelemetryPartitioner {
};
struct TelemetryStoreEntryBudgetor {
- size_t operator()(const BSONObj& key, const std::shared_ptr<TelemetryMetrics>& value) {
+ size_t operator()(const BSONObj& key, const std::shared_ptr<TelemetryEntry>& value) {
// The buget estimator for <key,value> pair in LRU cache accounts for size of value
- // (TelemetryMetrics) size of the key, and size of the key's underlying data struture
+ // (TelemetryEntry) size of the key, and size of the key's underlying data struture
// (BSONObj).
- return sizeof(TelemetryMetrics) + sizeof(BSONObj) + key.objsize();
+ return sizeof(TelemetryEntry) + sizeof(BSONObj) + key.objsize();
}
};
using TelemetryStore = PartitionedCache<BSONObj,
- std::shared_ptr<TelemetryMetrics>,
+ std::shared_ptr<TelemetryEntry>,
TelemetryStoreEntryBudgetor,
TelemetryPartitioner,
SimpleBSONObjComparator::Hasher,
@@ -211,10 +196,10 @@ TelemetryStore& getTelemetryStore(OperationContext* opCtx);
*
* Note that calling this affects internal state. It should be called once for each request for
* which telemetry may be collected.
- * TODO SERVER-76557 remove request-specific registers, leave only registerRequest
+ * TODO SERVER-73152 remove request-specific registers, leave only registerRequest
*/
void registerAggRequest(const AggregateCommandRequest& request, OperationContext* opCtx);
-void registerRequest(const RequestShapifier&,
+void registerRequest(std::unique_ptr<RequestShapifier> requestShapifier,
const NamespaceString& collection,
OperationContext* opCtx,
const boost::intrusive_ptr<ExpressionContext>& expCtx);
@@ -224,7 +209,7 @@ void registerRequest(const RequestShapifier&,
*/
void writeTelemetry(OperationContext* opCtx,
boost::optional<BSONObj> telemetryKey,
- const BSONObj& cmdObj,
+ std::unique_ptr<RequestShapifier> requestShapifier,
uint64_t queryExecMicros,
uint64_t docsReturned);
@@ -235,6 +220,6 @@ void writeTelemetry(OperationContext* opCtx,
BSONObj makeTelemetryKey(const FindCommandRequest& findCommand,
const SerializationOptions& opts,
const boost::intrusive_ptr<ExpressionContext>& expCtx,
- boost::optional<const TelemetryMetrics&> existingMetrics = boost::none);
+ boost::optional<const TelemetryEntry&> existingMetrics = boost::none);
} // namespace telemetry
} // namespace mongo
diff --git a/src/mongo/db/query/telemetry_store_test.cpp b/src/mongo/db/query/telemetry_store_test.cpp
index ccbf85574b3..3e4ea4ccd59 100644
--- a/src/mongo/db/query/telemetry_store_test.cpp
+++ b/src/mongo/db/query/telemetry_store_test.cpp
@@ -40,8 +40,35 @@
#include "mongo/unittest/unittest.h"
namespace mongo::telemetry {
+/**
+ * A default hmac application strategy that generates easy to check results for testing purposes.
+ */
+std::string applyHmacForTest(StringData s) {
+ return str::stream() << "HASH<" << s << ">";
+}
+class TelemetryStoreTest : public ServiceContextTest {
+public:
+ BSONObj makeTelemetryKeyFindRequest(
+ FindCommandRequest fcr,
+ const boost::intrusive_ptr<ExpressionContext>& expCtx,
+ bool applyHmac = false,
+ LiteralSerializationPolicy literalPolicy = LiteralSerializationPolicy::kUnchanged) {
+ FindRequestShapifier findShapifier(fcr, expCtx->opCtx);
-class TelemetryStoreTest : public ServiceContextTest {};
+ SerializationOptions opts;
+ if (literalPolicy != LiteralSerializationPolicy::kUnchanged) {
+ // TODO SERVER-75419 Use only 'literalPolicy.'
+ opts.replacementForLiteralArgs = "?";
+ opts.literalPolicy = literalPolicy;
+ }
+
+ if (applyHmac) {
+ opts.applyHmacToIdentifiers = true;
+ opts.identifierHmacPolicy = applyHmacForTest;
+ }
+ return findShapifier.makeTelemetryKey(opts, expCtx);
+ }
+};
TEST_F(TelemetryStoreTest, BasicUsage) {
TelemetryStore telStore{5000000, 1000};
@@ -52,11 +79,10 @@ TEST_F(TelemetryStoreTest, BasicUsage) {
};
auto collectMetrics = [&](BSONObj& key) {
- std::shared_ptr<TelemetryMetrics> metrics;
+ std::shared_ptr<TelemetryEntry> metrics;
auto lookupResult = telStore.lookup(key);
if (!lookupResult.isOK()) {
- telStore.put(
- key, std::make_shared<TelemetryMetrics>(BSONObj(), boost::none, NamespaceString{}));
+ telStore.put(key, std::make_shared<TelemetryEntry>(nullptr, NamespaceString{}));
lookupResult = telStore.lookup(key);
}
metrics = *lookupResult.getValue();
@@ -95,7 +121,7 @@ TEST_F(TelemetryStoreTest, BasicUsage) {
int numKeys = 0;
telStore.forEach(
- [&](const BSONObj& key, const std::shared_ptr<TelemetryMetrics>& entry) { numKeys++; });
+ [&](const BSONObj& key, const std::shared_ptr<TelemetryEntry>& entry) { numKeys++; });
ASSERT_EQ(numKeys, 2);
}
@@ -109,37 +135,24 @@ TEST_F(TelemetryStoreTest, EvictEntries) {
for (int i = 0; i < 20; i++) {
auto query = BSON("query" + std::to_string(i) << 1 << "xEquals" << 42);
- telStore.put(query,
- std::make_shared<TelemetryMetrics>(BSONObj(), boost::none, NamespaceString{}));
+ telStore.put(query, std::make_shared<TelemetryEntry>(nullptr, NamespaceString{}));
}
int numKeys = 0;
telStore.forEach(
- [&](const BSONObj& key, const std::shared_ptr<TelemetryMetrics>& entry) { numKeys++; });
+ [&](const BSONObj& key, const std::shared_ptr<TelemetryEntry>& entry) { numKeys++; });
- int entriesPerPartition = (cacheSize / numPartitions) / (46 + sizeof(TelemetryMetrics));
+ int entriesPerPartition = (cacheSize / numPartitions) / (46 + sizeof(TelemetryEntry));
ASSERT_EQ(numKeys, entriesPerPartition * numPartitions);
}
-/**
- * A default hmac application strategy that generates easy to check results for testing purposes.
- */
-std::string applyHmacForTest(StringData s) {
- return str::stream() << "HASH<" << s << ">";
-}
TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
auto expCtx = make_intrusive<ExpressionContextForTest>();
FindCommandRequest fcr(NamespaceStringOrUUID(NamespaceString("testDB.testColl")));
- FindRequestShapifier findShapifier(fcr, expCtx->opCtx);
fcr.setFilter(BSON("a" << 1));
- SerializationOptions opts;
- // TODO SERVER-75419 Use only 'literalPolicy.'
- opts.replacementForLiteralArgs = "?";
- opts.literalPolicy = LiteralSerializationPolicy::kToDebugTypeString;
- opts.applyHmacToIdentifiers = true;
- opts.identifierHmacPolicy = applyHmacForTest;
- auto hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ auto key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
@@ -156,11 +169,12 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
}
}
})",
- hmacApplied);
+ key);
// Add sort.
fcr.setSort(BSON("sortVal" << 1 << "otherSort" << -1));
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -180,11 +194,12 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
}
}
})",
- hmacApplied);
+ key);
// Add inclusion projection.
fcr.setProjection(BSON("e" << true << "f" << true));
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -209,14 +224,15 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
}
}
})",
- hmacApplied);
+ key);
// Add let.
fcr.setLet(BSON("var1"
<< "$a"
<< "var2"
<< "const1"));
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -245,13 +261,14 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
}
}
})",
- hmacApplied);
+ key);
// Add hinting fields.
fcr.setHint(BSON("z" << 1 << "c" << 1));
fcr.setMax(BSON("z" << 25));
fcr.setMin(BSON("z" << 80));
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -290,7 +307,7 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
}
}
})",
- hmacApplied);
+ key);
// Add the literal redaction fields.
fcr.setLimit(5);
@@ -299,7 +316,8 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
fcr.setMaxTimeMS(1000);
fcr.setNoCursorTimeout(false);
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -342,7 +360,7 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
"maxTimeMS": "?number"
}
})",
- hmacApplied);
+ key);
// Add the fields that shouldn't be hmacApplied.
fcr.setSingleBatch(true);
@@ -352,7 +370,8 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
fcr.setShowRecordId(true);
fcr.setAwaitData(false);
fcr.setMirrored(true);
- hmacApplied = findShapifier.makeTelemetryKey(opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -401,7 +420,7 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestAllFields) {
"mirrored": "?bool"
}
})",
- hmacApplied);
+ key);
}
TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestEmptyFields) {
@@ -416,7 +435,7 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsFindCommandRequestEmptyFields) {
opts.applyHmacToIdentifiers = true;
opts.identifierHmacPolicy = applyHmacForTest;
- auto hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ auto hmacApplied = findShapifier.makeTelemetryKey(opts, expCtx);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -437,15 +456,12 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsHintsWithOptions) {
FindRequestShapifier findShapifier(fcr, expCtx->opCtx);
fcr.setFilter(BSON("b" << 1));
- SerializationOptions opts;
- // TODO SERVER-75419 Use only 'literalPolicy.'
- opts.replacementForLiteralArgs = "?";
- opts.literalPolicy = LiteralSerializationPolicy::kToDebugTypeString;
fcr.setHint(BSON("z" << 1 << "c" << 1));
fcr.setMax(BSON("z" << 25));
fcr.setMin(BSON("z" << 80));
- auto hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ auto key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, false, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
@@ -472,13 +488,14 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsHintsWithOptions) {
}
}
})",
- hmacApplied);
+ key);
// Test with a string hint. Note that this is the internal representation of the string hint
// generated at parse time.
fcr.setHint(BSON("$hint"
<< "z"));
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, false, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -503,14 +520,10 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsHintsWithOptions) {
}
}
})",
- hmacApplied);
+ key);
fcr.setHint(BSON("z" << 1 << "c" << 1));
- opts.identifierHmacPolicy = applyHmacForTest;
- opts.applyHmacToIdentifiers = true;
- opts.replacementForLiteralArgs = boost::none;
- opts.literalPolicy = LiteralSerializationPolicy::kUnchanged;
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(fcr, expCtx, true, LiteralSerializationPolicy::kUnchanged);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -536,12 +549,10 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsHintsWithOptions) {
}
}
})",
- hmacApplied);
+ key);
- // TODO SERVER-75419 Use only 'literalPolicy.'
- opts.replacementForLiteralArgs = "?";
- opts.literalPolicy = LiteralSerializationPolicy::kToDebugTypeString;
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -567,11 +578,12 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsHintsWithOptions) {
}
}
})",
- hmacApplied);
+ key);
// Test that $natural comes through unmodified.
fcr.setHint(BSON("$natural" << -1));
- hmacApplied = telemetry::makeTelemetryKey(fcr, opts, expCtx);
+ key = makeTelemetryKeyFindRequest(
+ fcr, expCtx, true, LiteralSerializationPolicy::kToDebugTypeString);
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
@@ -596,7 +608,7 @@ TEST_F(TelemetryStoreTest, CorrectlyRedactsHintsWithOptions) {
}
}
})",
- hmacApplied);
+ key);
}
TEST_F(TelemetryStoreTest, DefinesLetVariables) {
@@ -613,11 +625,12 @@ TEST_F(TelemetryStoreTest, DefinesLetVariables) {
const auto cmdObj = fcr.toBSON(BSON("$db"
<< "testDB"));
- TelemetryMetrics testMetrics{cmdObj, boost::none, fcr.getNamespaceOrUUID()};
+ TelemetryEntry testMetrics{std::make_unique<telemetry::FindRequestShapifier>(fcr, opCtx.get()),
+ fcr.getNamespaceOrUUID()};
bool applyHmacToIdentifiers = false;
auto hmacApplied =
- testMetrics.applyHmacToKey(cmdObj, applyHmacToIdentifiers, std::string{}, opCtx.get());
+ testMetrics.makeTelemetryKey(cmdObj, applyHmacToIdentifiers, std::string{}, opCtx.get());
// As the query never moves through registerFindRequest and hmac is not enabled,
// makeTelemetryKey() never gets called and consequently the query never gets shapified.
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
@@ -647,7 +660,7 @@ TEST_F(TelemetryStoreTest, DefinesLetVariables) {
// do the hashing, so we'll just stick with the big long strings here for now.
applyHmacToIdentifiers = true;
hmacApplied =
- testMetrics.applyHmacToKey(cmdObj, applyHmacToIdentifiers, std::string{}, opCtx.get());
+ testMetrics.makeTelemetryKey(cmdObj, applyHmacToIdentifiers, std::string{}, opCtx.get());
ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
R"({
"queryShape": {
diff --git a/src/mongo/s/commands/cluster_find_cmd.h b/src/mongo/s/commands/cluster_find_cmd.h
index aa6c2873c8a..942e0893434 100644
--- a/src/mongo/s/commands/cluster_find_cmd.h
+++ b/src/mongo/s/commands/cluster_find_cmd.h
@@ -225,11 +225,11 @@ public:
MatchExpressionParser::kAllowAllSpecialFeatures));
if (!_didDoFLERewrite) {
- telemetry::registerRequest(
- telemetry::FindRequestShapifier(cq->getFindCommandRequest(), opCtx),
- cq->nss(),
- opCtx,
- cq->getExpCtx());
+ telemetry::registerRequest(std::make_unique<telemetry::FindRequestShapifier>(
+ cq->getFindCommandRequest(), opCtx),
+ cq->nss(),
+ opCtx,
+ cq->getExpCtx());
}
try {
diff --git a/src/mongo/s/query/cluster_aggregation_planner.cpp b/src/mongo/s/query/cluster_aggregation_planner.cpp
index aab9d729ae7..5aa643c0a85 100644
--- a/src/mongo/s/query/cluster_aggregation_planner.cpp
+++ b/src/mongo/s/query/cluster_aggregation_planner.cpp
@@ -367,7 +367,7 @@ BSONObj establishMergingMongosCursor(OperationContext* opCtx,
opDebug.additiveMetrics.nBatches = 1;
CurOp::get(opCtx)->setEndOfOpMetrics(responseBuilder.numDocs());
if (exhausted) {
- collectTelemetryMongos(opCtx, ccc->getOriginatingCommand());
+ collectTelemetryMongos(opCtx, ccc->getRequestShapifier());
} else {
collectTelemetryMongos(opCtx, ccc);
}
diff --git a/src/mongo/s/query/cluster_client_cursor.h b/src/mongo/s/query/cluster_client_cursor.h
index 8f0e7d79460..1f0d9be54a7 100644
--- a/src/mongo/s/query/cluster_client_cursor.h
+++ b/src/mongo/s/query/cluster_client_cursor.h
@@ -266,6 +266,12 @@ public:
*/
virtual bool shouldOmitDiagnosticInformation() const = 0;
+ /**
+ * Returns and releases ownership of the RequestShapifier associated with the request this
+ * cursor is handling.
+ */
+ virtual std::unique_ptr<telemetry::RequestShapifier> getRequestShapifier() = 0;
+
protected:
// Metrics that are accumulated over the lifetime of the cursor, incremented with each getMore.
// Useful for diagnostics like telemetry.
diff --git a/src/mongo/s/query/cluster_client_cursor_impl.cpp b/src/mongo/s/query/cluster_client_cursor_impl.cpp
index 249841b1dfa..9cc44be6811 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_impl.cpp
@@ -75,7 +75,8 @@ ClusterClientCursorImpl::ClusterClientCursorImpl(OperationContext* opCtx,
_lastUseDate(_createdDate),
_queryHash(CurOp::get(opCtx)->debug().queryHash),
_shouldOmitDiagnosticInformation(CurOp::get(opCtx)->debug().shouldOmitDiagnosticInformation),
- _telemetryStoreKey(CurOp::get(opCtx)->debug().telemetryStoreKey) {
+ _telemetryStoreKey(CurOp::get(opCtx)->debug().telemetryStoreKey),
+ _telemetryRequestShapifier(std::move(CurOp::get(opCtx)->debug().telemetryRequestShapifier)) {
dassert(!_params.compareWholeSortKeyOnRouter ||
SimpleBSONObjComparator::kInstance.evaluate(
_params.sortToApplyOnRouter == AsyncResultsMerger::kWholeSortKeySortPattern));
@@ -138,7 +139,7 @@ void ClusterClientCursorImpl::kill(OperationContext* opCtx) {
if (_telemetryStoreKey && opCtx) {
telemetry::writeTelemetry(opCtx,
_telemetryStoreKey,
- getOriginatingCommand(),
+ std::move(_telemetryRequestShapifier),
_metrics.executionTime.value_or(Microseconds{0}).count(),
_metrics.nreturned.value_or(0));
}
@@ -282,4 +283,8 @@ bool ClusterClientCursorImpl::shouldOmitDiagnosticInformation() const {
return _shouldOmitDiagnosticInformation;
}
+std::unique_ptr<telemetry::RequestShapifier> ClusterClientCursorImpl::getRequestShapifier() {
+ return std::move(_telemetryRequestShapifier);
+}
+
} // namespace mongo
diff --git a/src/mongo/s/query/cluster_client_cursor_impl.h b/src/mongo/s/query/cluster_client_cursor_impl.h
index 61a980c35bf..8f23c25ff02 100644
--- a/src/mongo/s/query/cluster_client_cursor_impl.h
+++ b/src/mongo/s/query/cluster_client_cursor_impl.h
@@ -120,6 +120,8 @@ public:
bool shouldOmitDiagnosticInformation() const final;
+ std::unique_ptr<telemetry::RequestShapifier> getRequestShapifier() final;
+
public:
/**
* Constructs a CCC whose result set is generated by a mock execution stage.
@@ -184,6 +186,9 @@ private:
// If boost::none, telemetry should not be collected for this cursor.
boost::optional<BSONObj> _telemetryStoreKey;
+ // The RequestShapifier used by telemetry to shapify the request payload into the telemetry
+ // store key.
+ std::unique_ptr<telemetry::RequestShapifier> _telemetryRequestShapifier;
// Tracks if kill() has been called on the cursor. Multiple calls to kill() is an error.
bool _hasBeenKilled = false;
diff --git a/src/mongo/s/query/cluster_client_cursor_mock.cpp b/src/mongo/s/query/cluster_client_cursor_mock.cpp
index 12ede48cee9..e495227b704 100644
--- a/src/mongo/s/query/cluster_client_cursor_mock.cpp
+++ b/src/mongo/s/query/cluster_client_cursor_mock.cpp
@@ -170,4 +170,8 @@ bool ClusterClientCursorMock::shouldOmitDiagnosticInformation() const {
return false;
}
+std::unique_ptr<telemetry::RequestShapifier> ClusterClientCursorMock::getRequestShapifier() {
+ return nullptr;
+}
+
} // namespace mongo
diff --git a/src/mongo/s/query/cluster_client_cursor_mock.h b/src/mongo/s/query/cluster_client_cursor_mock.h
index 78a53708893..131ca234287 100644
--- a/src/mongo/s/query/cluster_client_cursor_mock.h
+++ b/src/mongo/s/query/cluster_client_cursor_mock.h
@@ -33,6 +33,7 @@
#include <functional>
#include <queue>
+#include "mongo/db/query/request_shapifier.h"
#include "mongo/db/session/logical_session_id.h"
#include "mongo/s/query/cluster_client_cursor.h"
@@ -120,6 +121,8 @@ public:
bool shouldOmitDiagnosticInformation() const final;
+ std::unique_ptr<telemetry::RequestShapifier> getRequestShapifier() final;
+
private:
bool _killed = false;
std::queue<StatusWith<ClusterQueryResult>> _resultsQueue;
diff --git a/src/mongo/s/query/cluster_cursor_manager.cpp b/src/mongo/s/query/cluster_cursor_manager.cpp
index 313f283a5b5..1cfbd7bf700 100644
--- a/src/mongo/s/query/cluster_cursor_manager.cpp
+++ b/src/mongo/s/query/cluster_cursor_manager.cpp
@@ -591,14 +591,15 @@ StatusWith<ClusterClientCursorGuard> ClusterCursorManager::_detachCursor(WithLoc
return std::move(cursor);
}
-void collectTelemetryMongos(OperationContext* opCtx, const BSONObj& originatingCommand) {
+void collectTelemetryMongos(OperationContext* opCtx,
+ std::unique_ptr<telemetry::RequestShapifier> requestShapifier) {
// If we haven't registered a cursor to prepare for getMore requests, we record
// telemetry directly.
auto&& opDebug = CurOp::get(opCtx)->debug();
telemetry::writeTelemetry(
opCtx,
opDebug.telemetryStoreKey,
- originatingCommand,
+ std::move(requestShapifier),
opDebug.additiveMetrics.executionTime.value_or(Microseconds{0}).count(),
opDebug.additiveMetrics.nreturned.value_or(0));
}
diff --git a/src/mongo/s/query/cluster_cursor_manager.h b/src/mongo/s/query/cluster_cursor_manager.h
index d194e296b78..219dd773f82 100644
--- a/src/mongo/s/query/cluster_cursor_manager.h
+++ b/src/mongo/s/query/cluster_cursor_manager.h
@@ -610,7 +610,8 @@ private:
* Currently, telemetry is only collected for find and aggregate requests (and their subsequent
* getMore requests), so these should only be called from those request paths.
*/
-void collectTelemetryMongos(OperationContext* opCtx, const BSONObj& originatingCommand);
+void collectTelemetryMongos(OperationContext* opCtx,
+ std::unique_ptr<telemetry::RequestShapifier> requestShapifier);
void collectTelemetryMongos(OperationContext* opCtx, ClusterClientCursorGuard& cursor);
void collectTelemetryMongos(OperationContext* opCtx, ClusterCursorManager::PinnedCursor& cursor);
diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp
index 332a3641b0e..5b340ec098a 100644
--- a/src/mongo/s/query/cluster_find.cpp
+++ b/src/mongo/s/query/cluster_find.cpp
@@ -444,7 +444,7 @@ CursorId runQueryWithoutRetrying(OperationContext* opCtx,
if (shardIds.size() > 0) {
updateNumHostsTargetedMetrics(opCtx, cm, shardIds.size());
}
- collectTelemetryMongos(opCtx, ccc->getOriginatingCommand());
+ collectTelemetryMongos(opCtx, ccc->getRequestShapifier());
return CursorId(0);
}
diff --git a/src/mongo/s/query/store_possible_cursor.cpp b/src/mongo/s/query/store_possible_cursor.cpp
index 4336fe6d96c..38cec4024ed 100644
--- a/src/mongo/s/query/store_possible_cursor.cpp
+++ b/src/mongo/s/query/store_possible_cursor.cpp
@@ -98,7 +98,7 @@ StatusWith<BSONObj> storePossibleCursor(OperationContext* opCtx,
if (incomingCursorResponse.getValue().getCursorId() == CursorId(0)) {
opDebug.cursorExhausted = true;
- collectTelemetryMongos(opCtx, CurOp::get(opCtx)->opDescription());
+ collectTelemetryMongos(opCtx, std::move(opDebug.telemetryRequestShapifier));
return cmdResult;
}