Extract Mongo library instrumentation (#2789)
* Extract mongo library instrumentation * Finish * Drift * Cleanup * build twice * Spot
This commit is contained in:
parent
e87564ef12
commit
b416ece9c3
|
@ -121,6 +121,7 @@ public abstract class DatabaseClientTracer<CONNECTION, STATEMENT, SANITIZEDSTATE
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
protected String dbConnectionString(CONNECTION connection) {
|
protected String dbConnectionString(CONNECTION connection) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +130,7 @@ public abstract class DatabaseClientTracer<CONNECTION, STATEMENT, SANITIZEDSTATE
|
||||||
netPeerAttributes.setNetPeer(span, peerAddress(connection));
|
netPeerAttributes.setNetPeer(span, peerAddress(connection));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
protected abstract InetSocketAddress peerAddress(CONNECTION connection);
|
protected abstract InetSocketAddress peerAddress(CONNECTION connection);
|
||||||
|
|
||||||
protected void onStatement(
|
protected void onStatement(
|
||||||
|
|
|
@ -10,10 +10,9 @@ muzzle {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(':instrumentation:mongo:mongo-common:javaagent'))
|
implementation(project(':instrumentation:mongo:mongo-3.1:library'))
|
||||||
|
|
||||||
library group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
|
library group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
|
||||||
|
|
||||||
testImplementation project(':instrumentation:mongo:mongo-testing')
|
testImplementation project(':instrumentation:mongo:mongo-3.1:testing')
|
||||||
testImplementation group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '1.50.5'
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import com.mongodb.MongoClientOptions;
|
import com.mongodb.MongoClientOptions;
|
||||||
import com.mongodb.event.CommandListener;
|
import com.mongodb.event.CommandListener;
|
||||||
import io.opentelemetry.javaagent.instrumentation.mongo.TracingCommandListener;
|
|
||||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -68,11 +67,11 @@ public class MongoClientInstrumentationModule extends InstrumentationModule {
|
||||||
@Advice.This MongoClientOptions.Builder builder,
|
@Advice.This MongoClientOptions.Builder builder,
|
||||||
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
||||||
for (CommandListener commandListener : commandListeners) {
|
for (CommandListener commandListener : commandListeners) {
|
||||||
if (commandListener instanceof TracingCommandListener) {
|
if (commandListener == MongoInstrumentationSingletons.LISTENER) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.addCommandListener(new TracingCommandListener());
|
builder.addCommandListener(MongoInstrumentationSingletons.LISTENER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.mongo.v3_1;
|
||||||
|
|
||||||
|
import com.mongodb.event.CommandListener;
|
||||||
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTracing;
|
||||||
|
|
||||||
|
public final class MongoInstrumentationSingletons {
|
||||||
|
|
||||||
|
public static final CommandListener LISTENER =
|
||||||
|
MongoTracing.create(GlobalOpenTelemetry.get()).newCommandListener();
|
||||||
|
|
||||||
|
private MongoInstrumentationSingletons() {}
|
||||||
|
}
|
|
@ -3,167 +3,12 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import static io.opentelemetry.instrumentation.test.utils.PortUtils.UNUSABLE_PORT
|
|
||||||
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
|
||||||
|
|
||||||
import com.mongodb.MongoClient
|
|
||||||
import com.mongodb.MongoClientOptions
|
import com.mongodb.MongoClientOptions
|
||||||
import com.mongodb.MongoTimeoutException
|
import io.opentelemetry.instrumentation.mongo.v3_1.AbstractMongo31ClientTest
|
||||||
import com.mongodb.ServerAddress
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import com.mongodb.client.MongoCollection
|
|
||||||
import com.mongodb.client.MongoDatabase
|
|
||||||
import org.bson.BsonDocument
|
|
||||||
import org.bson.BsonString
|
|
||||||
import org.bson.Document
|
|
||||||
import spock.lang.Shared
|
|
||||||
|
|
||||||
class MongoClientTest extends AbstractMongoClientTest<MongoCollection<Document>> {
|
|
||||||
|
|
||||||
@Shared
|
|
||||||
MongoClient client
|
|
||||||
|
|
||||||
def setupSpec() throws Exception {
|
|
||||||
client = new MongoClient(new ServerAddress("localhost", port),
|
|
||||||
MongoClientOptions.builder()
|
|
||||||
.description("some-description")
|
|
||||||
.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
def cleanupSpec() throws Exception {
|
|
||||||
client?.close()
|
|
||||||
client = null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
class MongoClientTest extends AbstractMongo31ClientTest implements AgentTestTrait {
|
||||||
@Override
|
@Override
|
||||||
void createCollection(String dbName, String collectionName) {
|
void configureMongoClientOptions(MongoClientOptions.Builder options) {
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void createCollectionNoDescription(String dbName, String collectionName) {
|
|
||||||
MongoDatabase db = new MongoClient("localhost", port).getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName) {
|
|
||||||
def clientOptions = client.mongoClientOptions
|
|
||||||
def newClientOptions = MongoClientOptions.builder(clientOptions).build()
|
|
||||||
MongoDatabase db = new MongoClient(new ServerAddress("localhost", port), newClientOptions).getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int getCollection(String dbName, String collectionName) {
|
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
|
||||||
return db.getCollection(collectionName).count()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
MongoCollection<Document> setupInsert(String dbName, String collectionName) {
|
|
||||||
MongoCollection<Document> collection = runUnderTrace("setup") {
|
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
return db.getCollection(collectionName)
|
|
||||||
}
|
|
||||||
ignoreTracesAndClear(1)
|
|
||||||
return collection
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int insert(MongoCollection<Document> collection) {
|
|
||||||
collection.insertOne(new Document("password", "SECRET"))
|
|
||||||
return collection.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
MongoCollection<Document> setupUpdate(String dbName, String collectionName) {
|
|
||||||
MongoCollection<Document> collection = runUnderTrace("setup") {
|
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
def coll = db.getCollection(collectionName)
|
|
||||||
coll.insertOne(new Document("password", "OLDPW"))
|
|
||||||
return coll
|
|
||||||
}
|
|
||||||
ignoreTracesAndClear(1)
|
|
||||||
return collection
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int update(MongoCollection<Document> collection) {
|
|
||||||
def result = collection.updateOne(
|
|
||||||
new BsonDocument("password", new BsonString("OLDPW")),
|
|
||||||
new BsonDocument('$set', new BsonDocument("password", new BsonString("NEWPW"))))
|
|
||||||
collection.count()
|
|
||||||
return result.modifiedCount
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
MongoCollection<Document> setupDelete(String dbName, String collectionName) {
|
|
||||||
MongoCollection<Document> collection = runUnderTrace("setup") {
|
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
def coll = db.getCollection(collectionName)
|
|
||||||
coll.insertOne(new Document("password", "SECRET"))
|
|
||||||
return coll
|
|
||||||
}
|
|
||||||
ignoreTracesAndClear(1)
|
|
||||||
return collection
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
int delete(MongoCollection<Document> collection) {
|
|
||||||
def result = collection.deleteOne(new BsonDocument("password", new BsonString("SECRET")))
|
|
||||||
collection.count()
|
|
||||||
return result.deletedCount
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
MongoCollection<Document> setupGetMore(String dbName, String collectionName) {
|
|
||||||
MongoCollection<Document> 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
|
|
||||||
}
|
|
||||||
ignoreTracesAndClear(1)
|
|
||||||
return collection
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void getMore(MongoCollection<Document> collection) {
|
|
||||||
collection.find().filter(new Document("_id", new Document('$gte', 0)))
|
|
||||||
.batchSize(2).into(new ArrayList())
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void error(String dbName, String collectionName) {
|
|
||||||
MongoCollection<Document> collection = runUnderTrace("setup") {
|
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
return db.getCollection(collectionName)
|
|
||||||
}
|
|
||||||
ignoreTracesAndClear(1)
|
|
||||||
collection.updateOne(new BsonDocument(), new BsonDocument())
|
|
||||||
}
|
|
||||||
|
|
||||||
def "test client failure"() {
|
|
||||||
setup:
|
|
||||||
def options = MongoClientOptions.builder().serverSelectionTimeout(10).build()
|
|
||||||
def client = new MongoClient(new ServerAddress("localhost", UNUSABLE_PORT), [], options)
|
|
||||||
|
|
||||||
when:
|
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
|
||||||
db.createCollection(collectionName)
|
|
||||||
|
|
||||||
then:
|
|
||||||
thrown(MongoTimeoutException)
|
|
||||||
// Unfortunately not caught by our instrumentation.
|
|
||||||
assertTraces(0) {}
|
|
||||||
|
|
||||||
where:
|
|
||||||
dbName = "test_db"
|
|
||||||
collectionName = createCollectionName()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
apply from: "$rootDir/gradle/instrumentation-library.gradle"
|
||||||
|
apply plugin: "net.ltgt.errorprone"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
library group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
|
||||||
|
|
||||||
|
testImplementation project(':instrumentation:mongo:mongo-3.1:testing')
|
||||||
|
}
|
|
@ -3,13 +3,14 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.mongo;
|
package io.opentelemetry.instrumentation.mongo.v3_1;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
import com.mongodb.ServerAddress;
|
import com.mongodb.ServerAddress;
|
||||||
import com.mongodb.connection.ConnectionDescription;
|
import com.mongodb.connection.ConnectionDescription;
|
||||||
import com.mongodb.event.CommandStartedEvent;
|
import com.mongodb.event.CommandStartedEvent;
|
||||||
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
import io.opentelemetry.api.trace.SpanBuilder;
|
import io.opentelemetry.api.trace.SpanBuilder;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
import io.opentelemetry.instrumentation.api.tracer.DatabaseClientTracer;
|
||||||
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
|
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
|
||||||
|
@ -29,46 +30,49 @@ import org.bson.BsonDocument;
|
||||||
import org.bson.BsonValue;
|
import org.bson.BsonValue;
|
||||||
import org.bson.json.JsonWriter;
|
import org.bson.json.JsonWriter;
|
||||||
import org.bson.json.JsonWriterSettings;
|
import org.bson.json.JsonWriterSettings;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
|
||||||
public class MongoClientTracer
|
final class MongoClientTracer
|
||||||
extends DatabaseClientTracer<CommandStartedEvent, BsonDocument, String> {
|
extends DatabaseClientTracer<CommandStartedEvent, BsonDocument, String> {
|
||||||
private static final MongoClientTracer TRACER = new MongoClientTracer();
|
|
||||||
|
|
||||||
private final int maxNormalizedQueryLength;
|
private final int maxNormalizedQueryLength;
|
||||||
private final JsonWriterSettings jsonWriterSettings;
|
@Nullable private final JsonWriterSettings jsonWriterSettings;
|
||||||
|
|
||||||
public MongoClientTracer() {
|
MongoClientTracer(OpenTelemetry openTelemetry, int maxNormalizedQueryLength) {
|
||||||
this(32 * 1024);
|
super(openTelemetry, NetPeerAttributes.INSTANCE);
|
||||||
}
|
|
||||||
|
|
||||||
public MongoClientTracer(int maxNormalizedQueryLength) {
|
|
||||||
super(NetPeerAttributes.INSTANCE);
|
|
||||||
this.maxNormalizedQueryLength = maxNormalizedQueryLength;
|
this.maxNormalizedQueryLength = maxNormalizedQueryLength;
|
||||||
this.jsonWriterSettings = createJsonWriterSettings(maxNormalizedQueryLength);
|
this.jsonWriterSettings = createJsonWriterSettings(maxNormalizedQueryLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MongoClientTracer tracer() {
|
|
||||||
return TRACER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getInstrumentationName() {
|
protected String getInstrumentationName() {
|
||||||
return "io.opentelemetry.javaagent.mongo-common";
|
return "io.opentelemetry.javaagent.mongo-common";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
// TODO(anuraaga): Migrate off of StringWriter to avoid synchronization.
|
||||||
|
@SuppressWarnings("JdkObsolete")
|
||||||
protected String sanitizeStatement(BsonDocument command) {
|
protected String sanitizeStatement(BsonDocument command) {
|
||||||
StringWriter stringWriter = new StringWriter(128);
|
StringWriter stringWriter = new StringWriter(128);
|
||||||
writeScrubbed(command, new JsonWriter(stringWriter, jsonWriterSettings), true);
|
// jsonWriterSettings is generally not null but could be due to security manager or unknown
|
||||||
|
// API incompatibilities, which we can't detect by Muzzle because we use reflection.
|
||||||
|
JsonWriter jsonWriter =
|
||||||
|
jsonWriterSettings != null
|
||||||
|
? new JsonWriter(stringWriter, jsonWriterSettings)
|
||||||
|
: new JsonWriter(stringWriter);
|
||||||
|
writeScrubbed(command, jsonWriter, true);
|
||||||
// If using MongoDB driver >= 3.7, the substring invocation will be a no-op due to use of
|
// If using MongoDB driver >= 3.7, the substring invocation will be a no-op due to use of
|
||||||
// JsonWriterSettings.Builder.maxLength in the static initializer for JSON_WRITER_SETTINGS
|
// JsonWriterSettings.Builder.maxLength in the static initializer for JSON_WRITER_SETTINGS
|
||||||
return stringWriter
|
StringBuffer buf = stringWriter.getBuffer();
|
||||||
.getBuffer()
|
if (buf.length() <= maxNormalizedQueryLength) {
|
||||||
.substring(0, Math.min(maxNormalizedQueryLength, stringWriter.getBuffer().length()));
|
return buf.toString();
|
||||||
|
}
|
||||||
|
return buf.substring(0, maxNormalizedQueryLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String spanName(CommandStartedEvent event, BsonDocument document, String normalizedQuery) {
|
protected String spanName(
|
||||||
|
CommandStartedEvent event, BsonDocument document, String normalizedQuery) {
|
||||||
return conventionSpanName(dbName(event), event.getCommandName(), collectionName(event));
|
return conventionSpanName(dbName(event), event.getCommandName(), collectionName(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +96,7 @@ public class MongoClientTracer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
protected String dbConnectionString(CommandStartedEvent event) {
|
protected String dbConnectionString(CommandStartedEvent event) {
|
||||||
ConnectionDescription connectionDescription = event.getConnectionDescription();
|
ConnectionDescription connectionDescription = event.getConnectionDescription();
|
||||||
if (connectionDescription != null) {
|
if (connectionDescription != null) {
|
||||||
|
@ -109,6 +114,7 @@ public class MongoClientTracer
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
protected InetSocketAddress peerAddress(CommandStartedEvent event) {
|
protected InetSocketAddress peerAddress(CommandStartedEvent event) {
|
||||||
if (event.getConnectionDescription() != null
|
if (event.getConnectionDescription() != null
|
||||||
&& event.getConnectionDescription().getServerAddress() != null) {
|
&& event.getConnectionDescription().getServerAddress() != null) {
|
||||||
|
@ -130,7 +136,7 @@ public class MongoClientTracer
|
||||||
return event.getCommandName();
|
return event.getCommandName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Method IS_TRUNCATED_METHOD;
|
@Nullable private static final Method IS_TRUNCATED_METHOD;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
IS_TRUNCATED_METHOD =
|
IS_TRUNCATED_METHOD =
|
||||||
|
@ -140,6 +146,7 @@ public class MongoClientTracer
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private JsonWriterSettings createJsonWriterSettings(int maxNormalizedQueryLength) {
|
private JsonWriterSettings createJsonWriterSettings(int maxNormalizedQueryLength) {
|
||||||
JsonWriterSettings settings = null;
|
JsonWriterSettings settings = null;
|
||||||
try {
|
try {
|
||||||
|
@ -175,14 +182,17 @@ public class MongoClientTracer
|
||||||
builderClass.getMethod("build", (Class<?>[]) null).invoke(builder, (Object[]) null);
|
builderClass.getMethod("build", (Class<?>[]) null).invoke(builder, (Object[]) null);
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ignored) {
|
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException ignored) {
|
||||||
|
// Ignore
|
||||||
}
|
}
|
||||||
if (settings == null) {
|
if (settings == null) {
|
||||||
try {
|
try {
|
||||||
|
// Constructor removed in 4.0+ so use reflection. 4.0+ will have used the builder above.
|
||||||
settings = JsonWriterSettings.class.getConstructor(Boolean.TYPE).newInstance(false);
|
settings = JsonWriterSettings.class.getConstructor(Boolean.TYPE).newInstance(false);
|
||||||
} catch (InstantiationException
|
} catch (InstantiationException
|
||||||
| IllegalAccessException
|
| IllegalAccessException
|
||||||
| InvocationTargetException
|
| InvocationTargetException
|
||||||
| NoSuchMethodException ignored) {
|
| NoSuchMethodException ignored) {
|
||||||
|
// Ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,6 +274,7 @@ public class MongoClientTracer
|
||||||
"createIndexes",
|
"createIndexes",
|
||||||
"listIndexes"));
|
"listIndexes"));
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private static String collectionName(CommandStartedEvent event) {
|
private static String collectionName(CommandStartedEvent event) {
|
||||||
if (event.getCommandName().equals("getMore")) {
|
if (event.getCommandName().equals("getMore")) {
|
||||||
if (event.getCommand().containsKey("collection")) {
|
if (event.getCommand().containsKey("collection")) {
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.mongo.v3_1;
|
||||||
|
|
||||||
|
import com.mongodb.event.CommandListener;
|
||||||
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
|
|
||||||
|
/** Entrypoint to OpenTelemetry instrumentation of the MongoDB client. */
|
||||||
|
public final class MongoTracing {
|
||||||
|
|
||||||
|
/** Returns a new {@link MongoTracing} configured with the given {@link OpenTelemetry}. */
|
||||||
|
public static MongoTracing create(OpenTelemetry openTelemetry) {
|
||||||
|
return newBuilder(openTelemetry).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a new {@link MongoTracingBuilder} configured with the given {@link OpenTelemetry}. */
|
||||||
|
public static MongoTracingBuilder newBuilder(OpenTelemetry openTelemetry) {
|
||||||
|
return new MongoTracingBuilder(openTelemetry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final MongoClientTracer tracer;
|
||||||
|
|
||||||
|
MongoTracing(OpenTelemetry openTelemetry, int maxNormalizedQueryLength) {
|
||||||
|
this.tracer = new MongoClientTracer(openTelemetry, maxNormalizedQueryLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link CommandListener} that can be used with methods like {@link
|
||||||
|
* com.mongodb.MongoClientOptions.Builder#addCommandListener(CommandListener)}.
|
||||||
|
*/
|
||||||
|
public CommandListener newCommandListener() {
|
||||||
|
return new TracingCommandListener(tracer);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.mongo.v3_1;
|
||||||
|
|
||||||
|
import io.opentelemetry.api.OpenTelemetry;
|
||||||
|
|
||||||
|
/** A builder of {@link MongoTracing}. */
|
||||||
|
public final class MongoTracingBuilder {
|
||||||
|
|
||||||
|
// Visible for testing
|
||||||
|
static final int DEFAULT_MAX_NORMALIZED_QUERY_LENGTH = 32 * 1024;
|
||||||
|
|
||||||
|
private final OpenTelemetry openTelemetry;
|
||||||
|
|
||||||
|
private int maxNormalizedQueryLength = DEFAULT_MAX_NORMALIZED_QUERY_LENGTH;
|
||||||
|
|
||||||
|
MongoTracingBuilder(OpenTelemetry openTelemetry) {
|
||||||
|
this.openTelemetry = openTelemetry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the max length of recorded queries after normalization. Defaults to {@value
|
||||||
|
* DEFAULT_MAX_NORMALIZED_QUERY_LENGTH}.
|
||||||
|
*/
|
||||||
|
public MongoTracingBuilder setMaxNormalizedQueryLength(int maxNormalizedQueryLength) {
|
||||||
|
this.maxNormalizedQueryLength = maxNormalizedQueryLength;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a new {@link MongoTracing} with the settings of this {@link MongoTracingBuilder}. */
|
||||||
|
public MongoTracing build() {
|
||||||
|
return new MongoTracing(openTelemetry, maxNormalizedQueryLength);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,9 +3,7 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.opentelemetry.javaagent.instrumentation.mongo;
|
package io.opentelemetry.instrumentation.mongo.v3_1;
|
||||||
|
|
||||||
import static io.opentelemetry.javaagent.instrumentation.mongo.MongoClientTracer.tracer;
|
|
||||||
|
|
||||||
import com.mongodb.event.CommandFailedEvent;
|
import com.mongodb.event.CommandFailedEvent;
|
||||||
import com.mongodb.event.CommandListener;
|
import com.mongodb.event.CommandListener;
|
||||||
|
@ -15,13 +13,19 @@ import io.opentelemetry.context.Context;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class TracingCommandListener implements CommandListener {
|
final class TracingCommandListener implements CommandListener {
|
||||||
|
|
||||||
private final Map<Integer, Context> contextMap = new ConcurrentHashMap<>();
|
private final MongoClientTracer tracer;
|
||||||
|
private final Map<Integer, Context> contextMap;
|
||||||
|
|
||||||
|
TracingCommandListener(MongoClientTracer tracer) {
|
||||||
|
this.tracer = tracer;
|
||||||
|
contextMap = new ConcurrentHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void commandStarted(CommandStartedEvent event) {
|
public void commandStarted(CommandStartedEvent event) {
|
||||||
Context context = tracer().startSpan(Context.current(), event, event.getCommand());
|
Context context = tracer.startSpan(Context.current(), event, event.getCommand());
|
||||||
contextMap.put(event.getRequestId(), context);
|
contextMap.put(event.getRequestId(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +33,7 @@ public class TracingCommandListener implements CommandListener {
|
||||||
public void commandSucceeded(CommandSucceededEvent event) {
|
public void commandSucceeded(CommandSucceededEvent event) {
|
||||||
Context context = contextMap.remove(event.getRequestId());
|
Context context = contextMap.remove(event.getRequestId());
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
tracer().end(context);
|
tracer.end(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +41,7 @@ public class TracingCommandListener implements CommandListener {
|
||||||
public void commandFailed(CommandFailedEvent event) {
|
public void commandFailed(CommandFailedEvent event) {
|
||||||
Context context = contextMap.remove(event.getRequestId());
|
Context context = contextMap.remove(event.getRequestId());
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
tracer().endExceptionally(context, event.getThrowable());
|
tracer.endExceptionally(context, event.getThrowable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.mongo.v3_1
|
||||||
|
|
||||||
|
import com.mongodb.MongoClientOptions
|
||||||
|
import io.opentelemetry.instrumentation.test.LibraryTestTrait
|
||||||
|
|
||||||
|
class MongoClientTest extends AbstractMongo31ClientTest implements LibraryTestTrait {
|
||||||
|
@Override
|
||||||
|
void configureMongoClientOptions(MongoClientOptions.Builder options) {
|
||||||
|
options.addCommandListener(MongoTracing.create(openTelemetry).newCommandListener())
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,13 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.mongo.v3_1
|
||||||
|
|
||||||
|
import static io.opentelemetry.instrumentation.mongo.v3_1.MongoTracingBuilder.DEFAULT_MAX_NORMALIZED_QUERY_LENGTH
|
||||||
import static java.util.Arrays.asList
|
import static java.util.Arrays.asList
|
||||||
|
|
||||||
import com.mongodb.event.CommandStartedEvent
|
import com.mongodb.event.CommandStartedEvent
|
||||||
import io.opentelemetry.javaagent.instrumentation.mongo.MongoClientTracer
|
import io.opentelemetry.api.OpenTelemetry
|
||||||
import org.bson.BsonArray
|
import org.bson.BsonArray
|
||||||
import org.bson.BsonDocument
|
import org.bson.BsonDocument
|
||||||
import org.bson.BsonInt32
|
import org.bson.BsonInt32
|
||||||
|
@ -16,7 +19,7 @@ import spock.lang.Specification
|
||||||
class MongoClientTracerTest extends Specification {
|
class MongoClientTracerTest extends Specification {
|
||||||
def 'should sanitize statements to json'() {
|
def 'should sanitize statements to json'() {
|
||||||
setup:
|
setup:
|
||||||
def tracer = new MongoClientTracer()
|
def tracer = new MongoClientTracer(OpenTelemetry.noop(), DEFAULT_MAX_NORMALIZED_QUERY_LENGTH)
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
sanitizeStatementAcrossVersions(tracer,
|
sanitizeStatementAcrossVersions(tracer,
|
||||||
|
@ -36,7 +39,7 @@ class MongoClientTracerTest extends Specification {
|
||||||
|
|
||||||
def 'should only preserve string value if it is the value of the first top-level key'() {
|
def 'should only preserve string value if it is the value of the first top-level key'() {
|
||||||
setup:
|
setup:
|
||||||
def tracer = new MongoClientTracer()
|
def tracer = new MongoClientTracer(OpenTelemetry.noop(), DEFAULT_MAX_NORMALIZED_QUERY_LENGTH)
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
sanitizeStatementAcrossVersions(tracer,
|
sanitizeStatementAcrossVersions(tracer,
|
||||||
|
@ -48,7 +51,7 @@ class MongoClientTracerTest extends Specification {
|
||||||
|
|
||||||
def 'should truncate simple command'() {
|
def 'should truncate simple command'() {
|
||||||
setup:
|
setup:
|
||||||
def tracer = new MongoClientTracer(20)
|
def tracer = new MongoClientTracer(OpenTelemetry.noop(), 20)
|
||||||
|
|
||||||
def normalized = sanitizeStatementAcrossVersions(tracer,
|
def normalized = sanitizeStatementAcrossVersions(tracer,
|
||||||
new BsonDocument("cmd", new BsonString("c"))
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
|
@ -61,11 +64,11 @@ class MongoClientTracerTest extends Specification {
|
||||||
|
|
||||||
def 'should truncate array'() {
|
def 'should truncate array'() {
|
||||||
setup:
|
setup:
|
||||||
def tracer = new MongoClientTracer(27)
|
def tracer = new MongoClientTracer(OpenTelemetry.noop(), 27)
|
||||||
|
|
||||||
def normalized = sanitizeStatementAcrossVersions(tracer,
|
def normalized = sanitizeStatementAcrossVersions(tracer,
|
||||||
new BsonDocument("cmd", new BsonString("c"))
|
new BsonDocument("cmd", new BsonString("c"))
|
||||||
.append("f1", new BsonArray(Arrays.asList(new BsonString("c1"), new BsonString("c2"))))
|
.append("f1", new BsonArray(asList(new BsonString("c1"), new BsonString("c2"))))
|
||||||
.append("f2", new BsonString("c3")))
|
.append("f2", new BsonString("c3")))
|
||||||
expect:
|
expect:
|
||||||
// this can vary because of different whitespace for different mongo versions
|
// this can vary because of different whitespace for different mongo versions
|
||||||
|
@ -74,7 +77,7 @@ class MongoClientTracerTest extends Specification {
|
||||||
|
|
||||||
def 'test span name with no dbName'() {
|
def 'test span name with no dbName'() {
|
||||||
setup:
|
setup:
|
||||||
def tracer = new MongoClientTracer()
|
def tracer = new MongoClientTracer(OpenTelemetry.noop(), DEFAULT_MAX_NORMALIZED_QUERY_LENGTH)
|
||||||
def event = new CommandStartedEvent(
|
def event = new CommandStartedEvent(
|
||||||
0, null, null, command, new BsonDocument(command, new BsonInt32(1)))
|
0, null, null, command, new BsonDocument(command, new BsonInt32(1)))
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
apply from: "$rootDir/gradle/java.gradle"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api project(':instrumentation:mongo:mongo-testing')
|
||||||
|
|
||||||
|
compileOnly group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
|
||||||
|
|
||||||
|
implementation deps.groovy
|
||||||
|
implementation deps.opentelemetryApi
|
||||||
|
implementation deps.spock
|
||||||
|
}
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.mongo.v3_1
|
||||||
|
|
||||||
|
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
||||||
|
|
||||||
|
import com.mongodb.MongoClient
|
||||||
|
import com.mongodb.MongoClientOptions
|
||||||
|
import com.mongodb.MongoTimeoutException
|
||||||
|
import com.mongodb.ServerAddress
|
||||||
|
import com.mongodb.client.MongoCollection
|
||||||
|
import com.mongodb.client.MongoDatabase
|
||||||
|
import io.opentelemetry.instrumentation.mongo.testing.AbstractMongoClientTest
|
||||||
|
import io.opentelemetry.instrumentation.test.utils.PortUtils
|
||||||
|
import org.bson.BsonDocument
|
||||||
|
import org.bson.BsonString
|
||||||
|
import org.bson.Document
|
||||||
|
import spock.lang.Shared
|
||||||
|
|
||||||
|
abstract class AbstractMongo31ClientTest extends AbstractMongoClientTest<MongoCollection<Document>> {
|
||||||
|
|
||||||
|
abstract void configureMongoClientOptions(MongoClientOptions.Builder options);
|
||||||
|
|
||||||
|
@Shared
|
||||||
|
MongoClient client
|
||||||
|
|
||||||
|
def setupSpec() throws Exception {
|
||||||
|
def options = MongoClientOptions.builder().description("some-description")
|
||||||
|
configureMongoClientOptions(options)
|
||||||
|
client = new MongoClient(new ServerAddress("localhost", port), options.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
def cleanupSpec() throws Exception {
|
||||||
|
client?.close()
|
||||||
|
client = null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollection(String dbName, String collectionName) {
|
||||||
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollectionNoDescription(String dbName, String collectionName) {
|
||||||
|
def options = MongoClientOptions.builder()
|
||||||
|
configureMongoClientOptions(options)
|
||||||
|
MongoDatabase db = new MongoClient(new ServerAddress("localhost", port), options.build()).getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName) {
|
||||||
|
def clientOptions = client.mongoClientOptions
|
||||||
|
def newClientOptions = MongoClientOptions.builder(clientOptions).build()
|
||||||
|
MongoDatabase db = new MongoClient(new ServerAddress("localhost", port), newClientOptions).getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollectionCallingBuildTwice(String dbName, String collectionName) {
|
||||||
|
def options = MongoClientOptions.builder().description("some-description")
|
||||||
|
configureMongoClientOptions(options)
|
||||||
|
options.build()
|
||||||
|
MongoDatabase db = new MongoClient(new ServerAddress("localhost", port), options.build()).getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int getCollection(String dbName, String collectionName) {
|
||||||
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
return db.getCollection(collectionName).count()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MongoCollection<Document> setupInsert(String dbName, String collectionName) {
|
||||||
|
MongoCollection<Document> collection = runUnderTrace("setup") {
|
||||||
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
return db.getCollection(collectionName)
|
||||||
|
}
|
||||||
|
ignoreTracesAndClear(1)
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int insert(MongoCollection<Document> collection) {
|
||||||
|
collection.insertOne(new Document("password", "SECRET"))
|
||||||
|
return collection.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MongoCollection<Document> setupUpdate(String dbName, String collectionName) {
|
||||||
|
MongoCollection<Document> collection = runUnderTrace("setup") {
|
||||||
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
def coll = db.getCollection(collectionName)
|
||||||
|
coll.insertOne(new Document("password", "OLDPW"))
|
||||||
|
return coll
|
||||||
|
}
|
||||||
|
ignoreTracesAndClear(1)
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int update(MongoCollection<Document> collection) {
|
||||||
|
def result = collection.updateOne(
|
||||||
|
new BsonDocument("password", new BsonString("OLDPW")),
|
||||||
|
new BsonDocument('$set', new BsonDocument("password", new BsonString("NEWPW"))))
|
||||||
|
collection.count()
|
||||||
|
return result.modifiedCount
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MongoCollection<Document> setupDelete(String dbName, String collectionName) {
|
||||||
|
MongoCollection<Document> collection = runUnderTrace("setup") {
|
||||||
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
def coll = db.getCollection(collectionName)
|
||||||
|
coll.insertOne(new Document("password", "SECRET"))
|
||||||
|
return coll
|
||||||
|
}
|
||||||
|
ignoreTracesAndClear(1)
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int delete(MongoCollection<Document> collection) {
|
||||||
|
def result = collection.deleteOne(new BsonDocument("password", new BsonString("SECRET")))
|
||||||
|
collection.count()
|
||||||
|
return result.deletedCount
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
MongoCollection<Document> setupGetMore(String dbName, String collectionName) {
|
||||||
|
MongoCollection<Document> 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
|
||||||
|
}
|
||||||
|
ignoreTracesAndClear(1)
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void getMore(MongoCollection<Document> collection) {
|
||||||
|
collection.find().filter(new Document("_id", new Document('$gte', 0)))
|
||||||
|
.batchSize(2).into(new ArrayList())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void error(String dbName, String collectionName) {
|
||||||
|
MongoCollection<Document> collection = runUnderTrace("setup") {
|
||||||
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
return db.getCollection(collectionName)
|
||||||
|
}
|
||||||
|
ignoreTracesAndClear(1)
|
||||||
|
collection.updateOne(new BsonDocument(), new BsonDocument())
|
||||||
|
}
|
||||||
|
|
||||||
|
def "test client failure"() {
|
||||||
|
setup:
|
||||||
|
def options = MongoClientOptions.builder().serverSelectionTimeout(10).build()
|
||||||
|
def client = new MongoClient(new ServerAddress("localhost", PortUtils.UNUSABLE_PORT), [], options)
|
||||||
|
|
||||||
|
when:
|
||||||
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
|
||||||
|
then:
|
||||||
|
thrown(MongoTimeoutException)
|
||||||
|
// Unfortunately not caught by our instrumentation.
|
||||||
|
assertTraces(0) {}
|
||||||
|
|
||||||
|
where:
|
||||||
|
dbName = "test_db"
|
||||||
|
collectionName = createCollectionName()
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,11 +19,10 @@ muzzle {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(':instrumentation:mongo:mongo-common:javaagent'))
|
implementation(project(':instrumentation:mongo:mongo-3.1:library'))
|
||||||
|
|
||||||
// a couple of test attribute verifications don't pass until 3.8.0
|
// a couple of test attribute verifications don't pass until 3.8.0
|
||||||
library group: 'org.mongodb', name: 'mongo-java-driver', version: '3.8.0'
|
library group: 'org.mongodb', name: 'mongo-java-driver', version: '3.8.0'
|
||||||
|
|
||||||
testImplementation project(':instrumentation:mongo:mongo-testing')
|
testImplementation project(':instrumentation:mongo:mongo-testing')
|
||||||
testImplementation group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '1.50.5'
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import com.mongodb.MongoClientSettings;
|
||||||
import com.mongodb.async.SingleResultCallback;
|
import com.mongodb.async.SingleResultCallback;
|
||||||
import com.mongodb.event.CommandListener;
|
import com.mongodb.event.CommandListener;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||||
import io.opentelemetry.javaagent.instrumentation.mongo.TracingCommandListener;
|
|
||||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -74,11 +73,11 @@ public class MongoClientInstrumentationModule extends InstrumentationModule {
|
||||||
@Advice.This MongoClientSettings.Builder builder,
|
@Advice.This MongoClientSettings.Builder builder,
|
||||||
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
||||||
for (CommandListener commandListener : commandListeners) {
|
for (CommandListener commandListener : commandListeners) {
|
||||||
if (commandListener instanceof TracingCommandListener) {
|
if (commandListener == MongoInstrumentationSingletons.LISTENER) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.addCommandListener(new TracingCommandListener());
|
builder.addCommandListener(MongoInstrumentationSingletons.LISTENER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.mongo.v3_7;
|
||||||
|
|
||||||
|
import com.mongodb.event.CommandListener;
|
||||||
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTracing;
|
||||||
|
|
||||||
|
public final class MongoInstrumentationSingletons {
|
||||||
|
|
||||||
|
public static final CommandListener LISTENER =
|
||||||
|
MongoTracing.create(GlobalOpenTelemetry.get()).newCommandListener();
|
||||||
|
|
||||||
|
private MongoInstrumentationSingletons() {}
|
||||||
|
}
|
|
@ -13,12 +13,14 @@ import com.mongodb.client.MongoClient
|
||||||
import com.mongodb.client.MongoClients
|
import com.mongodb.client.MongoClients
|
||||||
import com.mongodb.client.MongoCollection
|
import com.mongodb.client.MongoCollection
|
||||||
import com.mongodb.client.MongoDatabase
|
import com.mongodb.client.MongoDatabase
|
||||||
|
import io.opentelemetry.instrumentation.mongo.testing.AbstractMongoClientTest
|
||||||
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import org.bson.BsonDocument
|
import org.bson.BsonDocument
|
||||||
import org.bson.BsonString
|
import org.bson.BsonString
|
||||||
import org.bson.Document
|
import org.bson.Document
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
|
||||||
class MongoClientTest extends AbstractMongoClientTest<MongoCollection<Document>> {
|
class MongoClientTest extends AbstractMongoClientTest<MongoCollection<Document>> implements AgentTestTrait {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
MongoClient client
|
MongoClient client
|
||||||
|
@ -64,6 +66,19 @@ class MongoClientTest extends AbstractMongoClientTest<MongoCollection<Document>>
|
||||||
db.createCollection(collectionName)
|
db.createCollection(collectionName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollectionCallingBuildTwice(String dbName, String collectionName) {
|
||||||
|
def clientSettings = MongoClientSettings.builder()
|
||||||
|
.applyToClusterSettings({ builder ->
|
||||||
|
builder.hosts(Arrays.asList(
|
||||||
|
new ServerAddress("localhost", port)))
|
||||||
|
.description("some-description")
|
||||||
|
})
|
||||||
|
clientSettings.build()
|
||||||
|
MongoDatabase db = MongoClients.create(clientSettings.build()).getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int getCollection(String dbName, String collectionName) {
|
int getCollection(String dbName, String collectionName) {
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
|
|
@ -10,7 +10,7 @@ muzzle {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(':instrumentation:mongo:mongo-common:javaagent'))
|
implementation(project(':instrumentation:mongo:mongo-3.1:library'))
|
||||||
|
|
||||||
library group: 'org.mongodb', name: 'mongodb-driver-core', version: '4.0.0'
|
library group: 'org.mongodb', name: 'mongodb-driver-core', version: '4.0.0'
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import com.mongodb.MongoClientSettings;
|
||||||
import com.mongodb.event.CommandListener;
|
import com.mongodb.event.CommandListener;
|
||||||
import com.mongodb.internal.async.SingleResultCallback;
|
import com.mongodb.internal.async.SingleResultCallback;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||||
import io.opentelemetry.javaagent.instrumentation.mongo.TracingCommandListener;
|
|
||||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -74,11 +73,11 @@ public class MongoClientInstrumentationModule extends InstrumentationModule {
|
||||||
@Advice.This MongoClientSettings.Builder builder,
|
@Advice.This MongoClientSettings.Builder builder,
|
||||||
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
||||||
for (CommandListener commandListener : commandListeners) {
|
for (CommandListener commandListener : commandListeners) {
|
||||||
if (commandListener instanceof TracingCommandListener) {
|
if (commandListener == MongoInstrumentationSingletons.LISTENER) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.addCommandListener(new TracingCommandListener());
|
builder.addCommandListener(MongoInstrumentationSingletons.LISTENER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.mongo.v4_0;
|
||||||
|
|
||||||
|
import com.mongodb.event.CommandListener;
|
||||||
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTracing;
|
||||||
|
|
||||||
|
public final class MongoInstrumentationSingletons {
|
||||||
|
|
||||||
|
public static final CommandListener LISTENER =
|
||||||
|
MongoTracing.create(GlobalOpenTelemetry.get()).newCommandListener();
|
||||||
|
|
||||||
|
private MongoInstrumentationSingletons() {}
|
||||||
|
}
|
|
@ -5,12 +5,16 @@
|
||||||
|
|
||||||
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
||||||
|
|
||||||
|
import com.mongodb.MongoClientSettings
|
||||||
|
import com.mongodb.ServerAddress
|
||||||
import com.mongodb.client.result.DeleteResult
|
import com.mongodb.client.result.DeleteResult
|
||||||
import com.mongodb.client.result.UpdateResult
|
import com.mongodb.client.result.UpdateResult
|
||||||
import com.mongodb.reactivestreams.client.MongoClient
|
import com.mongodb.reactivestreams.client.MongoClient
|
||||||
import com.mongodb.reactivestreams.client.MongoClients
|
import com.mongodb.reactivestreams.client.MongoClients
|
||||||
import com.mongodb.reactivestreams.client.MongoCollection
|
import com.mongodb.reactivestreams.client.MongoCollection
|
||||||
import com.mongodb.reactivestreams.client.MongoDatabase
|
import com.mongodb.reactivestreams.client.MongoDatabase
|
||||||
|
import io.opentelemetry.instrumentation.mongo.testing.AbstractMongoClientTest
|
||||||
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
import org.bson.BsonDocument
|
import org.bson.BsonDocument
|
||||||
|
@ -21,7 +25,7 @@ import org.reactivestreams.Subscriber
|
||||||
import org.reactivestreams.Subscription
|
import org.reactivestreams.Subscription
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
|
||||||
class Mongo4ReactiveClientTest extends AbstractMongoClientTest<MongoCollection<Document>> {
|
class Mongo4ReactiveClientTest extends AbstractMongoClientTest<MongoCollection<Document>> implements AgentTestTrait {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
MongoClient client
|
MongoClient client
|
||||||
|
@ -52,6 +56,18 @@ class Mongo4ReactiveClientTest extends AbstractMongoClientTest<MongoCollection<D
|
||||||
throw new AssumptionViolatedException("not tested on 4.0")
|
throw new AssumptionViolatedException("not tested on 4.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollectionCallingBuildTwice(String dbName, String collectionName) {
|
||||||
|
def settings = MongoClientSettings.builder()
|
||||||
|
.applyToClusterSettings({ builder ->
|
||||||
|
builder.hosts(Arrays.asList(
|
||||||
|
new ServerAddress("localhost", port)))
|
||||||
|
})
|
||||||
|
settings.build()
|
||||||
|
MongoDatabase db = MongoClients.create(settings.build()).getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName).subscribe(toSubscriber {})
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int getCollection(String dbName, String collectionName) {
|
int getCollection(String dbName, String collectionName) {
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
|
|
@ -5,17 +5,21 @@
|
||||||
|
|
||||||
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
||||||
|
|
||||||
|
import com.mongodb.MongoClientSettings
|
||||||
|
import com.mongodb.ServerAddress
|
||||||
import com.mongodb.client.MongoClient
|
import com.mongodb.client.MongoClient
|
||||||
import com.mongodb.client.MongoClients
|
import com.mongodb.client.MongoClients
|
||||||
import com.mongodb.client.MongoCollection
|
import com.mongodb.client.MongoCollection
|
||||||
import com.mongodb.client.MongoDatabase
|
import com.mongodb.client.MongoDatabase
|
||||||
|
import io.opentelemetry.instrumentation.mongo.testing.AbstractMongoClientTest
|
||||||
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import org.bson.BsonDocument
|
import org.bson.BsonDocument
|
||||||
import org.bson.BsonString
|
import org.bson.BsonString
|
||||||
import org.bson.Document
|
import org.bson.Document
|
||||||
import org.junit.AssumptionViolatedException
|
import org.junit.AssumptionViolatedException
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
|
||||||
class MongoClientTest extends AbstractMongoClientTest<MongoCollection<Document>> {
|
class MongoClientTest extends AbstractMongoClientTest<MongoCollection<Document>> implements AgentTestTrait {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
MongoClient client
|
MongoClient client
|
||||||
|
@ -46,6 +50,18 @@ class MongoClientTest extends AbstractMongoClientTest<MongoCollection<Document>>
|
||||||
throw new AssumptionViolatedException("not tested on 4.0")
|
throw new AssumptionViolatedException("not tested on 4.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollectionCallingBuildTwice(String dbName, String collectionName) {
|
||||||
|
def settings = MongoClientSettings.builder()
|
||||||
|
.applyToClusterSettings({ builder ->
|
||||||
|
builder.hosts(Arrays.asList(
|
||||||
|
new ServerAddress("localhost", port)))
|
||||||
|
})
|
||||||
|
settings.build()
|
||||||
|
MongoDatabase db = MongoClients.create(settings.build()).getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int getCollection(String dbName, String collectionName) {
|
int getCollection(String dbName, String collectionName) {
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
|
|
@ -11,12 +11,11 @@ muzzle {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(':instrumentation:mongo:mongo-common:javaagent'))
|
implementation(project(':instrumentation:mongo:mongo-3.1:library'))
|
||||||
|
|
||||||
library group: 'org.mongodb', name: 'mongodb-driver-async', version: '3.3.0'
|
library group: 'org.mongodb', name: 'mongodb-driver-async', version: '3.3.0'
|
||||||
|
|
||||||
testImplementation project(':instrumentation:mongo:mongo-testing')
|
testImplementation project(':instrumentation:mongo:mongo-testing')
|
||||||
testImplementation group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '1.50.5'
|
|
||||||
|
|
||||||
testInstrumentation project(':instrumentation:mongo:mongo-3.7:javaagent')
|
testInstrumentation project(':instrumentation:mongo:mongo-3.7:javaagent')
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import com.mongodb.async.SingleResultCallback;
|
||||||
import com.mongodb.async.client.MongoClientSettings;
|
import com.mongodb.async.client.MongoClientSettings;
|
||||||
import com.mongodb.event.CommandListener;
|
import com.mongodb.event.CommandListener;
|
||||||
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge;
|
||||||
import io.opentelemetry.javaagent.instrumentation.mongo.TracingCommandListener;
|
|
||||||
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
import io.opentelemetry.javaagent.tooling.InstrumentationModule;
|
||||||
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
import io.opentelemetry.javaagent.tooling.TypeInstrumentation;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -76,11 +75,11 @@ public class MongoAsyncClientInstrumentationModule extends InstrumentationModule
|
||||||
@Advice.This MongoClientSettings.Builder builder,
|
@Advice.This MongoClientSettings.Builder builder,
|
||||||
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
@Advice.FieldValue("commandListeners") List<CommandListener> commandListeners) {
|
||||||
for (CommandListener commandListener : commandListeners) {
|
for (CommandListener commandListener : commandListeners) {
|
||||||
if (commandListener instanceof TracingCommandListener) {
|
if (commandListener == MongoInstrumentationSingletons.LISTENER) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.addCommandListener(new TracingCommandListener());
|
builder.addCommandListener(MongoInstrumentationSingletons.LISTENER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright The OpenTelemetry Authors
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.javaagent.instrumentation.mongoasync.v3_3;
|
||||||
|
|
||||||
|
import com.mongodb.event.CommandListener;
|
||||||
|
import io.opentelemetry.api.GlobalOpenTelemetry;
|
||||||
|
import io.opentelemetry.instrumentation.mongo.v3_1.MongoTracing;
|
||||||
|
|
||||||
|
public final class MongoInstrumentationSingletons {
|
||||||
|
|
||||||
|
public static final CommandListener LISTENER =
|
||||||
|
MongoTracing.create(GlobalOpenTelemetry.get()).newCommandListener();
|
||||||
|
|
||||||
|
private MongoInstrumentationSingletons() {}
|
||||||
|
}
|
|
@ -15,6 +15,8 @@ import com.mongodb.async.client.MongoDatabase
|
||||||
import com.mongodb.client.result.DeleteResult
|
import com.mongodb.client.result.DeleteResult
|
||||||
import com.mongodb.client.result.UpdateResult
|
import com.mongodb.client.result.UpdateResult
|
||||||
import com.mongodb.connection.ClusterSettings
|
import com.mongodb.connection.ClusterSettings
|
||||||
|
import io.opentelemetry.instrumentation.mongo.testing.AbstractMongoClientTest
|
||||||
|
import io.opentelemetry.instrumentation.test.AgentTestTrait
|
||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
import java.util.concurrent.CountDownLatch
|
import java.util.concurrent.CountDownLatch
|
||||||
import org.bson.BsonDocument
|
import org.bson.BsonDocument
|
||||||
|
@ -23,7 +25,7 @@ import org.bson.Document
|
||||||
import org.junit.AssumptionViolatedException
|
import org.junit.AssumptionViolatedException
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
|
||||||
class MongoAsyncClientTest extends AbstractMongoClientTest<MongoCollection<Document>> {
|
class MongoAsyncClientTest extends AbstractMongoClientTest<MongoCollection<Document>> implements AgentTestTrait{
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
MongoClient client
|
MongoClient client
|
||||||
|
@ -64,6 +66,19 @@ class MongoAsyncClientTest extends AbstractMongoClientTest<MongoCollection<Docum
|
||||||
db.createCollection(collectionName, toCallback {})
|
db.createCollection(collectionName, toCallback {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void createCollectionCallingBuildTwice(String dbName, String collectionName) {
|
||||||
|
def settings = MongoClientSettings.builder()
|
||||||
|
.clusterSettings(
|
||||||
|
ClusterSettings.builder()
|
||||||
|
.description("some-description")
|
||||||
|
.applyConnectionString(new ConnectionString("mongodb://localhost:$port"))
|
||||||
|
.build())
|
||||||
|
settings.build()
|
||||||
|
MongoDatabase db = MongoClients.create(settings.build()).getDatabase(dbName)
|
||||||
|
db.createCollection(collectionName, toCallback {})
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
int getCollection(String dbName, String collectionName) {
|
int getCollection(String dbName, String collectionName) {
|
||||||
MongoDatabase db = client.getDatabase(dbName)
|
MongoDatabase db = client.getDatabase(dbName)
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
// not applying $rootDir/gradle/instrumentation.gradle because that brings running tests with agent
|
|
||||||
// infrastructure, and this module only wants to run unit tests
|
|
||||||
|
|
||||||
ext.mavenGroupId = 'io.opentelemetry.javaagent.instrumentation'
|
|
||||||
|
|
||||||
apply from: "$rootDir/gradle/java.gradle"
|
|
||||||
apply from: "$rootDir/gradle/publish.gradle"
|
|
||||||
|
|
||||||
archivesBaseName = projectDir.parentFile.name
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
compileOnly project(':instrumentation-api')
|
|
||||||
compileOnly project(':javaagent-api')
|
|
||||||
compileOnly group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
|
|
||||||
|
|
||||||
testImplementation project(':instrumentation-api')
|
|
||||||
testImplementation project(':javaagent-api')
|
|
||||||
testImplementation group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
|
|
||||||
}
|
|
|
@ -3,11 +3,13 @@
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
package io.opentelemetry.instrumentation.mongo.testing
|
||||||
|
|
||||||
import static io.opentelemetry.api.trace.SpanKind.CLIENT
|
import static io.opentelemetry.api.trace.SpanKind.CLIENT
|
||||||
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.basicSpan
|
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.basicSpan
|
||||||
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
|
||||||
|
|
||||||
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
|
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
|
||||||
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
|
||||||
import io.opentelemetry.sdk.trace.data.SpanData
|
import io.opentelemetry.sdk.trace.data.SpanData
|
||||||
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
|
||||||
|
@ -17,7 +19,7 @@ import org.testcontainers.containers.GenericContainer
|
||||||
import org.testcontainers.containers.output.Slf4jLogConsumer
|
import org.testcontainers.containers.output.Slf4jLogConsumer
|
||||||
import spock.lang.Shared
|
import spock.lang.Shared
|
||||||
|
|
||||||
abstract class AbstractMongoClientTest<T> extends AgentInstrumentationSpecification {
|
abstract class AbstractMongoClientTest<T> extends InstrumentationSpecification {
|
||||||
|
|
||||||
@Shared
|
@Shared
|
||||||
GenericContainer mongodb
|
GenericContainer mongodb
|
||||||
|
@ -50,6 +52,8 @@ abstract class AbstractMongoClientTest<T> extends AgentInstrumentationSpecificat
|
||||||
// This test asserts that duplicate traces are not created in those cases.
|
// This test asserts that duplicate traces are not created in those cases.
|
||||||
abstract void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName)
|
abstract void createCollectionWithAlreadyBuiltClientOptions(String dbName, String collectionName)
|
||||||
|
|
||||||
|
abstract void createCollectionCallingBuildTwice(String dbName, String collectionName)
|
||||||
|
|
||||||
abstract int getCollection(String dbName, String collectionName)
|
abstract int getCollection(String dbName, String collectionName)
|
||||||
|
|
||||||
abstract T setupInsert(String dbName, String collectionName)
|
abstract T setupInsert(String dbName, String collectionName)
|
||||||
|
@ -120,6 +124,29 @@ abstract class AbstractMongoClientTest<T> extends AgentInstrumentationSpecificat
|
||||||
collectionName = createCollectionName()
|
collectionName = createCollectionName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "test create collection calling build twice"() {
|
||||||
|
when:
|
||||||
|
runUnderTrace("parent") {
|
||||||
|
createCollectionCallingBuildTwice(dbName, collectionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
then:
|
||||||
|
assertTraces(1) {
|
||||||
|
trace(0, 2) {
|
||||||
|
basicSpan(it, 0, "parent")
|
||||||
|
mongoSpan(it, 1, "create", collectionName, dbName, span(0)) {
|
||||||
|
assert it == "{\"create\":\"$collectionName\",\"capped\":\"?\"}" ||
|
||||||
|
it == "{\"create\": \"$collectionName\", \"capped\": \"?\", \"\$db\": \"?\", \"\$readPreference\": {\"mode\": \"?\"}}"
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
where:
|
||||||
|
dbName = "test_db"
|
||||||
|
collectionName = createCollectionName()
|
||||||
|
}
|
||||||
|
|
||||||
def "test get collection"() {
|
def "test get collection"() {
|
||||||
when:
|
when:
|
||||||
def count = runUnderTrace("parent") {
|
def count = runUnderTrace("parent") {
|
|
@ -186,10 +186,11 @@ include ':instrumentation:logback:logback-1.0:library'
|
||||||
include ':instrumentation:logback:logback-1.0:testing'
|
include ':instrumentation:logback:logback-1.0:testing'
|
||||||
include ':instrumentation:methods:javaagent'
|
include ':instrumentation:methods:javaagent'
|
||||||
include ':instrumentation:mongo:mongo-3.1:javaagent'
|
include ':instrumentation:mongo:mongo-3.1:javaagent'
|
||||||
|
include ':instrumentation:mongo:mongo-3.1:library'
|
||||||
|
include ':instrumentation:mongo:mongo-3.1:testing'
|
||||||
include ':instrumentation:mongo:mongo-3.7:javaagent'
|
include ':instrumentation:mongo:mongo-3.7:javaagent'
|
||||||
include ':instrumentation:mongo:mongo-4.0:javaagent'
|
include ':instrumentation:mongo:mongo-4.0:javaagent'
|
||||||
include ':instrumentation:mongo:mongo-async-3.3:javaagent'
|
include ':instrumentation:mongo:mongo-async-3.3:javaagent'
|
||||||
include ':instrumentation:mongo:mongo-common:javaagent'
|
|
||||||
include ':instrumentation:mongo:mongo-testing'
|
include ':instrumentation:mongo:mongo-testing'
|
||||||
include ':instrumentation:netty:netty-3.8:javaagent'
|
include ':instrumentation:netty:netty-3.8:javaagent'
|
||||||
include ':instrumentation:netty:netty-4.0:javaagent'
|
include ':instrumentation:netty:netty-4.0:javaagent'
|
||||||
|
|
Loading…
Reference in New Issue