From d093a561b9b473751478b2dfbe9386c427122a70 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Thu, 19 Nov 2020 19:26:27 -0500 Subject: [PATCH] Report only known collection names in MongoClientTracer (#1625) (#1662) * Report only known collection names in MongoClientTracer (#1625) * Use allow-list of commands that are known to use collection name as the value of the command * Special-case getMore command, which uses a different field for the collection name * Add create, drop, and createIndexes to list of commands with collection name as their values --- .../src/test/groovy/MongoClientTest.groovy | 30 ++++++++++++ .../src/test/groovy/MongoClientTest.groovy | 30 ++++++++++++ .../mongo/MongoClientTracer.java | 46 +++++++++++++++++-- 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/instrumentation/mongo/mongo-3.1/src/test/groovy/MongoClientTest.groovy b/instrumentation/mongo/mongo-3.1/src/test/groovy/MongoClientTest.groovy index 68cfa372b6..d8834b17b5 100644 --- a/instrumentation/mongo/mongo-3.1/src/test/groovy/MongoClientTest.groovy +++ b/instrumentation/mongo/mongo-3.1/src/test/groovy/MongoClientTest.groovy @@ -211,6 +211,36 @@ class MongoClientTest extends MongoBaseTest { collectionName = "testCollection" } + def "test collection name for getMore command"() { + setup: + MongoCollection collection = runUnderTrace("setup") { + MongoDatabase db = client.getDatabase(dbName) + def coll = db.getCollection(collectionName) + coll.insertMany([new Document("_id", 0), new Document("_id", 1), new Document("_id", 2)]) + return coll + } + TEST_WRITER.waitForTraces(1) + TEST_WRITER.clear() + + when: + collection.find().filter(new Document("_id", new Document('$gte', 0))) + .batchSize(2).into(new ArrayList()) + + then: + assertTraces(2) { + trace(0, 1) { + mongoSpan(it, 0, "find", collectionName, dbName, '{"find":"testCollection","filter":{"_id":{"$gte":"?"}},"batchSize":"?"}') + } + trace(1, 1) { + mongoSpan(it, 0, "getMore", collectionName, dbName, '{"getMore":"?","collection":"?","batchSize":"?"}') + } + } + + where: + dbName = "test_db" + collectionName = "testCollection" + } + def "test error"() { setup: MongoCollection collection = runUnderTrace("setup") { diff --git a/instrumentation/mongo/mongo-3.7/src/test/groovy/MongoClientTest.groovy b/instrumentation/mongo/mongo-3.7/src/test/groovy/MongoClientTest.groovy index 430ca695d8..d80ddb5339 100644 --- a/instrumentation/mongo/mongo-3.7/src/test/groovy/MongoClientTest.groovy +++ b/instrumentation/mongo/mongo-3.7/src/test/groovy/MongoClientTest.groovy @@ -221,6 +221,36 @@ class MongoClientTest extends MongoBaseTest { collectionName = "testCollection" } + def "test collection name for getMore command"() { + setup: + MongoCollection collection = runUnderTrace("setup") { + MongoDatabase db = client.getDatabase(dbName) + def coll = db.getCollection(collectionName) + coll.insertMany([new Document("_id", 0), new Document("_id", 1), new Document("_id", 2)]) + return coll + } + TEST_WRITER.waitForTraces(1) + TEST_WRITER.clear() + + when: + collection.find().filter(new Document("_id", new Document('$gte', 0))) + .batchSize(2).into(new ArrayList()) + + then: + assertTraces(2) { + trace(0, 1) { + mongoSpan(it, 0, "find", collectionName, dbName, '{"find":"testCollection","filter":{"_id":{"$gte":"?"}},"batchSize":"?"}') + } + trace(1, 1) { + mongoSpan(it, 0, "getMore", collectionName, dbName, '{"getMore":"?","collection":"?","batchSize":"?"}') + } + } + + where: + dbName = "test_db" + collectionName = "testCollection" + } + def "test error"() { setup: MongoCollection collection = runUnderTrace("setup") { diff --git a/instrumentation/mongo/mongo-common/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/MongoClientTracer.java b/instrumentation/mongo/mongo-common/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/MongoClientTracer.java index 600310f738..1043e76bbc 100644 --- a/instrumentation/mongo/mongo-common/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/MongoClientTracer.java +++ b/instrumentation/mongo/mongo-common/src/main/java/io/opentelemetry/javaagent/instrumentation/mongo/MongoClientTracer.java @@ -5,6 +5,8 @@ package io.opentelemetry.javaagent.instrumentation.mongo; +import static java.util.Arrays.asList; + import com.mongodb.ServerAddress; import com.mongodb.connection.ConnectionDescription; import com.mongodb.event.CommandStartedEvent; @@ -17,8 +19,11 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.util.Arrays; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonValue; @@ -106,6 +111,13 @@ public class MongoClientTracer extends DatabaseClientTracer UNSCRUBBED_FIELDS = + asList("ordered", "insert", "count", "find", "create"); + private JsonWriterSettings createJsonWriterSettings(int maxNormalizedQueryLength) { JsonWriterSettings settings = new JsonWriterSettings(false); try { @@ -212,10 +224,38 @@ public class MongoClientTracer extends DatabaseClientTracer COMMANDS_WITH_COLLECTION_NAME_AS_VALUE = + new HashSet<>( + asList( + "aggregate", + "count", + "distinct", + "mapReduce", + "geoSearch", + "delete", + "find", + "killCursors", + "findAndModify", + "insert", + "update", + "create", + "drop", + "createIndexes", + "listIndexes")); + private static String collectionName(CommandStartedEvent event) { - BsonValue collectionValue = event.getCommand().get(event.getCommandName()); - if (collectionValue != null && collectionValue.isString()) { - return collectionValue.asString().getValue(); + if (event.getCommandName().equals("getMore")) { + if (event.getCommand().containsKey("collection")) { + BsonValue collectionValue = event.getCommand().get("collection"); + if (collectionValue.isString()) { + return event.getCommand().getString("collection").getValue(); + } + } + } else if (COMMANDS_WITH_COLLECTION_NAME_AS_VALUE.contains(event.getCommandName())) { + BsonValue commandValue = event.getCommand().get(event.getCommandName()); + if (commandValue != null && commandValue.isString()) { + return commandValue.asString().getValue(); + } } return null; }