diff --git a/pom.xml b/pom.xml
index ed0dce4796..321477a286 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-mongo-micrometer-SNAPSHOT
pom
Spring Data MongoDB
diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml
index c28a240d2c..b61040e965 100644
--- a/spring-data-mongodb-benchmarks/pom.xml
+++ b/spring-data-mongodb-benchmarks/pom.xml
@@ -7,7 +7,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-mongo-micrometer-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml
index 0412911f82..7d91980c2c 100644
--- a/spring-data-mongodb-distribution/pom.xml
+++ b/spring-data-mongodb-distribution/pom.xml
@@ -15,7 +15,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-mongo-micrometer-SNAPSHOT
../pom.xml
@@ -41,7 +41,7 @@
generate-metrics-metadata
- prepare-package
+ generate-resources
java
@@ -52,7 +52,7 @@
generate-tracing-metadata
- prepare-package
+ generate-resources
java
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index 1f8c5b28a8..9553be436c 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -13,7 +13,7 @@
org.springframework.data
spring-data-mongodb-parent
- 4.0.0-SNAPSHOT
+ 4.0.0-mongo-micrometer-SNAPSHOT
../pom.xml
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/ContextProviderFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/ContextProviderFactory.java
new file mode 100644
index 0000000000..2357b334a2
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/ContextProviderFactory.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb.observability;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+
+import org.reactivestreams.Subscriber;
+import org.springframework.data.repository.util.ReactiveWrappers;
+import org.springframework.data.repository.util.ReactiveWrappers.ReactiveLibrary;
+import org.springframework.util.ClassUtils;
+
+import com.mongodb.ContextProvider;
+import com.mongodb.RequestContext;
+import com.mongodb.client.SynchronousContextProvider;
+import com.mongodb.reactivestreams.client.ReactiveContextProvider;
+
+import io.micrometer.observation.Observation;
+import io.micrometer.observation.ObservationRegistry;
+import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
+import reactor.core.CoreSubscriber;
+
+/**
+ * Factory to create a {@link ContextProvider} to propagate the request context across tasks. Requires either
+ * {@link SynchronousContextProvider} or {@link ReactiveContextProvider} to be present.
+ *
+ * @author Mark Paluch
+ * @since 3.0
+ */
+public class ContextProviderFactory {
+
+ private static final boolean SYNCHRONOUS_PRESENT = ClassUtils
+ .isPresent("com.mongodb.client.SynchronousContextProvider", ContextProviderFactory.class.getClassLoader());
+
+ private static final boolean REACTIVE_PRESENT = ClassUtils.isPresent(
+ "com.mongodb.reactivestreams.client.ReactiveContextProvider", ContextProviderFactory.class.getClassLoader())
+ && ReactiveWrappers.isAvailable(ReactiveLibrary.PROJECT_REACTOR);
+
+ /**
+ * Create a {@link ContextProvider} given {@link ObservationRegistry}. The factory method attempts to create a
+ * {@link ContextProvider} that is capable to propagate request contexts across imperative or reactive usage,
+ * depending on their class path presence.
+ *
+ * @param observationRegistry must not be {@literal null}.
+ * @return
+ */
+ public static ContextProvider create(ObservationRegistry observationRegistry) {
+
+ if (SYNCHRONOUS_PRESENT && REACTIVE_PRESENT) {
+ return new CompositeContextProvider(observationRegistry);
+ }
+
+ if (SYNCHRONOUS_PRESENT) {
+ return new DefaultSynchronousContextProvider(observationRegistry);
+ }
+
+ if (REACTIVE_PRESENT) {
+ return DefaultReactiveContextProvider.INSTANCE;
+ }
+
+ throw new IllegalStateException(
+ "Cannot create ContextProvider. Neither SynchronousContextProvider nor ReactiveContextProvider is on the class path.");
+ }
+
+ record DefaultSynchronousContextProvider(
+ ObservationRegistry observationRegistry) implements SynchronousContextProvider {
+
+ @Override
+ public RequestContext getContext() {
+
+ MapRequestContext requestContext = new MapRequestContext();
+
+ Observation currentObservation = observationRegistry.getCurrentObservation();
+ if (currentObservation != null) {
+ requestContext.put(Observation.class, currentObservation);
+ }
+
+ return requestContext;
+ }
+
+ }
+
+ enum DefaultReactiveContextProvider implements ReactiveContextProvider {
+
+ INSTANCE;
+
+ @Override
+ public RequestContext getContext(Subscriber> subscriber) {
+
+ if (subscriber instanceof CoreSubscriber> cs) {
+
+ Map