diff --git a/bom/application/pom.xml b/bom/application/pom.xml
index 2a354f086715c..93fe0b51bf8d0 100644
--- a/bom/application/pom.xml
+++ b/bom/application/pom.xml
@@ -26,6 +26,7 @@
0.2.0
0.0.12
0.1.13
+ 0.1.5
0.34.3
3.0.18.Final
1.0.0.Final
@@ -2678,6 +2679,11 @@
opentracing-kafka-client
${opentracing-kafka.version}
+
+ io.opentracing.contrib
+ opentracing-mongo-common
+ ${opentracing-mongo.version}
+
io.rest-assured
rest-assured
diff --git a/docs/src/main/asciidoc/mongodb.adoc b/docs/src/main/asciidoc/mongodb.adoc
index 54fe32c7fe5a0..7d10df91b2b66 100644
--- a/docs/src/main/asciidoc/mongodb.adoc
+++ b/docs/src/main/asciidoc/mongodb.adoc
@@ -596,6 +596,12 @@ This behavior must first be enabled by setting the `quarkus.mongodb.metrics.enab
So when you access the `/q/metrics` endpoint of your application you will have information about the connection pool status.
When using link:microprofile-metrics[SmallRye Metrics], connection pool metrics will be available under the `vendor` scope.
+== Tracing
+
+If you are using the `quarkus-smallrye-opentracing` extension, `quarkus-mongodb-client` can register traces about the commands executed.
+This behavior must be enabled by setting the `quarkus.mongodb.tracing.enabled` property to `true` in your `application.properties` and adding the dependency `io.opentracing.contrib:opentracing-mongo-common` to your pom.xml (for more info read the link:opentracing#mongodb-client[OpenTracing - MongoDB client] section).
+
+Read the link:opentracing[OpenTracing] guide, for how to configure OpenTracing and how to use the Jaeger tracer.
== The legacy client
diff --git a/docs/src/main/asciidoc/opentracing.adoc b/docs/src/main/asciidoc/opentracing.adoc
index b3a2f67c293b5..ea5f10fea3ed6 100644
--- a/docs/src/main/asciidoc/opentracing.adoc
+++ b/docs/src/main/asciidoc/opentracing.adoc
@@ -257,6 +257,28 @@ mp.messaging.incoming.prices.interceptor.classes=io.opentracing.contrib.kafka.Tr
NOTE: `interceptor.classes` accept a list of classes separated by a comma.
+
+=== MongoDB client
+
+The https://github.com/opentracing-contrib/java-mongo-driver[Mongo Driver instrumentation] will add a span for each command executed by your application. To enable it, add the following dependency to your pom.xml:
+
+[source, xml]
+----
+
+ io.opentracing.contrib
+ opentracing-mongo-common
+
+----
+
+It contains the OpenTracing CommandListener that will be registered on the configuration of the mongo client.
+Following the link:mongodb[MongoDB guide], the command listener will be registered defining the config property as follows:
+
+[source, properties]
+----
+# Enable tracing commands in mongodb client
+quarkus.mongodb.tracing.enabled=true
+----
+
[[configuration-reference]]
== Jaeger Configuration Reference
diff --git a/extensions/mongodb-client/deployment/pom.xml b/extensions/mongodb-client/deployment/pom.xml
index 9750bfa790fcd..efd33d5fb0196 100644
--- a/extensions/mongodb-client/deployment/pom.xml
+++ b/extensions/mongodb-client/deployment/pom.xml
@@ -64,6 +64,27 @@
quarkus-resteasy-deployment
test
+
+ io.quarkus
+ quarkus-smallrye-opentracing-deployment
+ test
+
+
+ io.opentracing.contrib
+ opentracing-mongo-common
+ test
+
+
+ io.opentracing
+ opentracing-mock
+ test
+
+
+ io.opentracing
+ opentracing-util
+ test-jar
+ test
+
diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildTimeConfig.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildTimeConfig.java
index 166893f250f81..f6c4a7d58d251 100644
--- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildTimeConfig.java
+++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientBuildTimeConfig.java
@@ -18,6 +18,12 @@ public class MongoClientBuildTimeConfig {
@ConfigItem(name = "metrics.enabled")
public boolean metricsEnabled;
+ /**
+ * Whether or not tracing spans of driver commands are sent in case the smallrye-opentracing extension is present.
+ */
+ @ConfigItem(name = "tracing.enabled")
+ public boolean tracingEnabled;
+
/**
* If set to true, the default clients will always be created even if there are no injection points that use them
*/
diff --git a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java
index e3e7c99f4de3e..72ee208bd7b3e 100644
--- a/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java
+++ b/extensions/mongodb-client/deployment/src/main/java/io/quarkus/mongodb/deployment/MongoClientProcessor.java
@@ -35,6 +35,8 @@
import io.quarkus.arc.processor.BuildExtension;
import io.quarkus.arc.processor.DotNames;
import io.quarkus.arc.processor.InjectionPointInfo;
+import io.quarkus.deployment.Capabilities;
+import io.quarkus.deployment.Capability;
import io.quarkus.deployment.Feature;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
@@ -59,6 +61,7 @@
import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem;
public class MongoClientProcessor {
+ private static final String MONGODB_TRACING_COMMANDLISTENER_CLASSNAME = "io.quarkus.mongodb.tracing.MongoTracingCommandListener";
private static final DotName LEGACY_MONGO_CLIENT_ANNOTATION = DotName
.createSimple(io.quarkus.mongodb.runtime.MongoClientName.class.getName());
private static final DotName MONGO_CLIENT_ANNOTATION = DotName.createSimple(MongoClientName.class.getName());
@@ -93,10 +96,16 @@ BsonDiscriminatorBuildItem collectBsonDiscriminators(CombinedIndexBuildItem inde
}
@BuildStep
- CommandListenerBuildItem collectCommandListeners(CombinedIndexBuildItem indexBuildItem) {
+ CommandListenerBuildItem collectCommandListeners(CombinedIndexBuildItem indexBuildItem,
+ MongoClientBuildTimeConfig buildTimeConfig, Capabilities capabilities) {
Collection commandListenerClasses = indexBuildItem.getIndex()
.getAllKnownImplementors(DotName.createSimple(CommandListener.class.getName()));
- List names = commandListenerClasses.stream().map(ci -> ci.name().toString()).collect(Collectors.toList());
+ List names = commandListenerClasses.stream()
+ .map(ci -> ci.name().toString())
+ .collect(Collectors.toList());
+ if (buildTimeConfig.tracingEnabled && capabilities.isPresent(Capability.OPENTRACING)) {
+ names.add(MONGODB_TRACING_COMMANDLISTENER_CLASSNAME);
+ }
return new CommandListenerBuildItem(names);
}
diff --git a/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoTracingCommandListenerTest.java b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoTracingCommandListenerTest.java
new file mode 100644
index 0000000000000..05d872f5b6838
--- /dev/null
+++ b/extensions/mongodb-client/deployment/src/test/java/io/quarkus/mongodb/MongoTracingCommandListenerTest.java
@@ -0,0 +1,73 @@
+package io.quarkus.mongodb;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.inject.Inject;
+
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import com.mongodb.client.MongoClient;
+
+import io.opentracing.mock.MockSpan;
+import io.opentracing.mock.MockTracer;
+import io.opentracing.util.GlobalTracer;
+import io.opentracing.util.GlobalTracerTestUtil;
+import io.quarkus.mongodb.tracing.MongoTracingCommandListener;
+import io.quarkus.test.QuarkusUnitTest;
+
+/**
+ * Test the inclusion and config of the {@link MongoTracingCommandListener}.
+ *
+ * @see io.quarkus.smallrye.opentracing.deployment.TracingTest
+ */
+public class MongoTracingCommandListenerTest extends MongoTestBase {
+
+ @Inject
+ MongoClient client;
+
+ @RegisterExtension
+ static final QuarkusUnitTest config = new QuarkusUnitTest()
+ .setArchiveProducer(
+ () -> ShrinkWrap.create(JavaArchive.class).addClasses(MongoTestBase.class))
+ .withConfigurationResource("application-tracing-mongo.properties");
+
+ static MockTracer mockTracer = new MockTracer();
+ static {
+ GlobalTracer.register(mockTracer);
+ }
+
+ @BeforeEach
+ public void before() {
+ mockTracer.reset();
+ }
+
+ @AfterAll
+ public static void afterAll() {
+ GlobalTracerTestUtil.resetGlobalTracer();
+ }
+
+ @AfterEach
+ void cleanup() {
+ if (client != null) {
+ client.close();
+ }
+ }
+
+ @Test
+ void testClientInitialization() {
+ assertThat(mockTracer.finishedSpans()).isEmpty();
+
+ assertThat(client.listDatabaseNames().first()).isNotEmpty();
+
+ assertThat(mockTracer.finishedSpans()).hasSize(1);
+ MockSpan span = mockTracer.finishedSpans().get(0);
+ assertThat(span.operationName()).isEqualTo("listDatabases");
+ }
+
+}
diff --git a/extensions/mongodb-client/deployment/src/test/resources/application-tracing-mongo.properties b/extensions/mongodb-client/deployment/src/test/resources/application-tracing-mongo.properties
new file mode 100644
index 0000000000000..fc4f686e65cd5
--- /dev/null
+++ b/extensions/mongodb-client/deployment/src/test/resources/application-tracing-mongo.properties
@@ -0,0 +1,8 @@
+quarkus.mongodb.connection-string=mongodb://localhost:27018
+quarkus.mongodb.tracing.enabled=true
+
+
+quarkus.jaeger.enabled=true
+quarkus.jaeger.service-name=tracing-test
+quarkus.jaeger.sampler-param=1
+quarkus.jaeger.sampler-type=const
\ No newline at end of file
diff --git a/extensions/mongodb-client/runtime/pom.xml b/extensions/mongodb-client/runtime/pom.xml
index 83005556aeebd..a855d1c01b6b2 100644
--- a/extensions/mongodb-client/runtime/pom.xml
+++ b/extensions/mongodb-client/runtime/pom.xml
@@ -63,6 +63,17 @@
true
+
+ io.quarkus
+ quarkus-smallrye-opentracing
+ true
+
+
+ io.opentracing.contrib
+ opentracing-mongo-common
+ true
+
+
org.graalvm.nativeimage
svm
diff --git a/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/tracing/MongoTracingCommandListener.java b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/tracing/MongoTracingCommandListener.java
new file mode 100644
index 0000000000000..b43418b792333
--- /dev/null
+++ b/extensions/mongodb-client/runtime/src/main/java/io/quarkus/mongodb/tracing/MongoTracingCommandListener.java
@@ -0,0 +1,46 @@
+package io.quarkus.mongodb.tracing;
+
+import com.mongodb.event.CommandFailedEvent;
+import com.mongodb.event.CommandListener;
+import com.mongodb.event.CommandStartedEvent;
+import com.mongodb.event.CommandSucceededEvent;
+
+import io.opentracing.contrib.mongo.common.TracingCommandListener;
+import io.opentracing.util.GlobalTracer;
+import io.vertx.core.logging.Logger;
+import io.vertx.core.logging.LoggerFactory;
+
+/**
+ * Command Listener for Mongo client delegated to {@link TracingCommandListener}.
+ *
+ */
+public class MongoTracingCommandListener implements CommandListener {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(MongoTracingCommandListener.class);
+
+ private TracingCommandListener delegate;
+
+ public MongoTracingCommandListener() {
+ this.delegate = new TracingCommandListener.Builder(GlobalTracer.get()).build();
+ LOGGER.debug("TracingCommandListener Delegate created");
+ }
+
+ @Override
+ public void commandStarted(CommandStartedEvent event) {
+ LOGGER.trace("commandStarted event " + event.getCommandName());
+ delegate.commandStarted(event);
+ }
+
+ @Override
+ public void commandFailed(CommandFailedEvent event) {
+ LOGGER.trace("commandFailed event " + event.getCommandName());
+ delegate.commandFailed(event);
+ }
+
+ @Override
+ public void commandSucceeded(CommandSucceededEvent event) {
+ LOGGER.trace("commandSucceded event " + event.getCommandName());
+ delegate.commandSucceeded(event);
+ }
+
+}