diff options
author | Will Buerger <will.buerger@mongodb.com> | 2023-05-05 13:36:36 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-05-05 16:42:44 +0000 |
commit | 72e24ba9bbc1c3043d35d47e30cda75075ff3d95 (patch) | |
tree | 4673ecbe265e23f3a01cac1e187c0290c71110a3 | |
parent | d66daf618a9005eaba4a8c9fa3746ef27ab80427 (diff) | |
download | mongo-72e24ba9bbc1c3043d35d47e30cda75075ff3d95.tar.gz |
SERVER-76557: Keep RequestShapifiers in telemetry store
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; } |