Skip to content

Commit 5007e68

Browse files
committed
Polishing.
See: spring-projects#4216
1 parent 3ea4e0f commit 5007e68

22 files changed

+590
-602
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mongodb.observability;
17+
18+
import java.util.Map;
19+
import java.util.Map.Entry;
20+
import java.util.stream.Collectors;
21+
22+
import org.reactivestreams.Subscriber;
23+
import org.springframework.data.repository.util.ReactiveWrappers;
24+
import org.springframework.data.repository.util.ReactiveWrappers.ReactiveLibrary;
25+
import org.springframework.util.ClassUtils;
26+
27+
import com.mongodb.ContextProvider;
28+
import com.mongodb.RequestContext;
29+
import com.mongodb.client.SynchronousContextProvider;
30+
import com.mongodb.reactivestreams.client.ReactiveContextProvider;
31+
32+
import io.micrometer.observation.Observation;
33+
import io.micrometer.observation.ObservationRegistry;
34+
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
35+
import reactor.core.CoreSubscriber;
36+
37+
/**
38+
* Factory to create a {@link ContextProvider} to propagate the request context across tasks. Requires either
39+
* {@link SynchronousContextProvider} or {@link ReactiveContextProvider} to be present.
40+
*
41+
* @author Mark Paluch
42+
* @since 3.0
43+
*/
44+
public class ContextProviderFactory {
45+
46+
private static final boolean SYNCHRONOUS_PRESENT = ClassUtils
47+
.isPresent("com.mongodb.client.SynchronousContextProvider", ContextProviderFactory.class.getClassLoader());
48+
49+
private static final boolean REACTIVE_PRESENT = ClassUtils.isPresent(
50+
"com.mongodb.reactivestreams.client.ReactiveContextProvider", ContextProviderFactory.class.getClassLoader())
51+
&& ReactiveWrappers.isAvailable(ReactiveLibrary.PROJECT_REACTOR);
52+
53+
/**
54+
* Create a {@link ContextProvider} given {@link ObservationRegistry}. The factory method attempts to create a
55+
* {@link ContextProvider} that is capable to propagate request contexts across imperative or reactive usage,
56+
* depending on their class path presence.
57+
*
58+
* @param observationRegistry must not be {@literal null}.
59+
* @return
60+
*/
61+
public static ContextProvider create(ObservationRegistry observationRegistry) {
62+
63+
if (SYNCHRONOUS_PRESENT && REACTIVE_PRESENT) {
64+
return new CompositeContextProvider(observationRegistry);
65+
}
66+
67+
if (SYNCHRONOUS_PRESENT) {
68+
return new DefaultSynchronousContextProvider(observationRegistry);
69+
}
70+
71+
if (REACTIVE_PRESENT) {
72+
return DefaultReactiveContextProvider.INSTANCE;
73+
}
74+
75+
throw new IllegalStateException(
76+
"Cannot create ContextProvider. Neither SynchronousContextProvider nor ReactiveContextProvider is on the class path.");
77+
}
78+
79+
record DefaultSynchronousContextProvider(
80+
ObservationRegistry observationRegistry) implements SynchronousContextProvider {
81+
82+
@Override
83+
public RequestContext getContext() {
84+
85+
MapRequestContext requestContext = new MapRequestContext();
86+
87+
Observation currentObservation = observationRegistry.getCurrentObservation();
88+
if (currentObservation != null) {
89+
requestContext.put(Observation.class, currentObservation);
90+
}
91+
92+
return requestContext;
93+
}
94+
95+
}
96+
97+
enum DefaultReactiveContextProvider implements ReactiveContextProvider {
98+
99+
INSTANCE;
100+
101+
@Override
102+
public RequestContext getContext(Subscriber<?> subscriber) {
103+
104+
if (subscriber instanceof CoreSubscriber<?> cs) {
105+
106+
Map<Object, Object> map = cs.currentContext().stream()
107+
.collect(Collectors.toConcurrentMap(Entry::getKey, Entry::getValue));
108+
if (map.containsKey(ObservationThreadLocalAccessor.KEY)) {
109+
map.put(Observation.class, map.get(ObservationThreadLocalAccessor.KEY));
110+
}
111+
112+
return new MapRequestContext(map);
113+
}
114+
115+
return new MapRequestContext();
116+
}
117+
}
118+
119+
record CompositeContextProvider(DefaultSynchronousContextProvider synchronousContextProvider)
120+
implements
121+
SynchronousContextProvider,
122+
ReactiveContextProvider {
123+
124+
CompositeContextProvider(ObservationRegistry observationRegistry) {
125+
this(new DefaultSynchronousContextProvider(observationRegistry));
126+
}
127+
128+
@Override
129+
public RequestContext getContext() {
130+
return synchronousContextProvider.getContext();
131+
}
132+
133+
@Override
134+
public RequestContext getContext(Subscriber<?> subscriber) {
135+
return DefaultReactiveContextProvider.INSTANCE.getContext(subscriber);
136+
}
137+
}
138+
139+
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/DefaultMongoHandlerObservationConvention.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2022 the original author or authors.
2+
* Copyright 2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,30 +15,32 @@
1515
*/
1616
package org.springframework.data.mongodb.observability;
1717

18-
import io.micrometer.common.KeyValue;
19-
import io.micrometer.common.KeyValues;
20-
2118
import org.springframework.data.mongodb.observability.MongoObservation.HighCardinalityCommandKeyNames;
2219
import org.springframework.data.mongodb.observability.MongoObservation.LowCardinalityCommandKeyNames;
20+
import org.springframework.lang.Nullable;
21+
import org.springframework.util.ObjectUtils;
2322

2423
import com.mongodb.connection.ConnectionDescription;
2524
import com.mongodb.connection.ConnectionId;
2625
import com.mongodb.event.CommandStartedEvent;
2726

27+
import io.micrometer.common.KeyValue;
28+
import io.micrometer.common.KeyValues;
29+
2830
/**
2931
* Default {@link MongoHandlerObservationConvention} implementation.
3032
*
3133
* @author Greg Turnquist
32-
* @since 4.0.0
34+
* @since 4
3335
*/
34-
public class DefaultMongoHandlerObservationConvention implements MongoHandlerObservationConvention {
36+
class DefaultMongoHandlerObservationConvention implements MongoHandlerObservationConvention {
3537

3638
@Override
3739
public KeyValues getLowCardinalityKeyValues(MongoHandlerContext context) {
3840

3941
KeyValues keyValues = KeyValues.empty();
4042

41-
if (context.getCollectionName() != null) {
43+
if (!ObjectUtils.isEmpty(context.getCollectionName())) {
4244
keyValues = keyValues
4345
.and(LowCardinalityCommandKeyNames.MONGODB_COLLECTION.withValue(context.getCollectionName()));
4446
}
@@ -58,12 +60,18 @@ public KeyValues getHighCardinalityKeyValues(MongoHandlerContext context) {
5860
HighCardinalityCommandKeyNames.MONGODB_COMMAND.withValue(context.getCommandStartedEvent().getCommandName()));
5961
}
6062

63+
@Override
64+
public String getContextualName(MongoHandlerContext context) {
65+
return context.getContextualName();
66+
}
67+
6168
/**
6269
* Extract connection details for a MongoDB connection into a {@link KeyValue}.
6370
*
6471
* @param event
6572
* @return
6673
*/
74+
@Nullable
6775
private static KeyValue connectionTag(CommandStartedEvent event) {
6876

6977
ConnectionDescription connectionDescription = event.getConnectionDescription();

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/EnableMongoObservability.java

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2022 the original author or authors.
2+
* Copyright 2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,15 +28,15 @@
2828
* @author Greg Turnquist
2929
* @since 4.0.0
3030
*/
31-
class TraceRequestContext implements RequestContext {
31+
class MapRequestContext implements RequestContext {
3232

3333
private final Map<Object, Object> map;
3434

35-
public TraceRequestContext() {
35+
public MapRequestContext() {
3636
this(new HashMap<>());
3737
}
3838

39-
public TraceRequestContext(Map<Object, Object> context) {
39+
public MapRequestContext(Map<Object, Object> context) {
4040
this.map = context;
4141
}
4242

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/MongoHandlerContext.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2022 the original author or authors.
2+
* Copyright 2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,8 +15,6 @@
1515
*/
1616
package org.springframework.data.mongodb.observability;
1717

18-
import io.micrometer.observation.Observation;
19-
2018
import java.util.Arrays;
2119
import java.util.LinkedHashSet;
2220
import java.util.Set;
@@ -30,17 +28,23 @@
3028
import com.mongodb.event.CommandStartedEvent;
3129
import com.mongodb.event.CommandSucceededEvent;
3230

31+
import io.micrometer.observation.Observation;
32+
import io.micrometer.observation.transport.Kind;
33+
import io.micrometer.observation.transport.SenderContext;
34+
3335
/**
3436
* A {@link Observation.Context} that contains MongoDB events.
3537
*
3638
* @author Marcin Grzejszczak
3739
* @author Greg Turnquist
3840
* @since 4.0.0
3941
*/
40-
public class MongoHandlerContext extends Observation.Context {
42+
public class MongoHandlerContext extends SenderContext<Object> {
4143

4244
/**
43-
* @see https://docs.mongodb.com/manual/reference/command for the command reference
45+
* @see <a href=
46+
* "https://docs.mongodb.com/manual/reference/command">https://docs.mongodb.com/manual/reference/command</a> for
47+
* the command reference
4448
*/
4549
private static final Set<String> COMMANDS_WITH_COLLECTION_NAME = new LinkedHashSet<>(
4650
Arrays.asList("aggregate", "count", "distinct", "mapReduce", "geoSearch", "delete", "find", "findAndModify",
@@ -55,7 +59,7 @@ public class MongoHandlerContext extends Observation.Context {
5559
private CommandFailedEvent commandFailedEvent;
5660

5761
public MongoHandlerContext(CommandStartedEvent commandStartedEvent, RequestContext requestContext) {
58-
62+
super((carrier, key, value) -> {}, Kind.CLIENT);
5963
this.commandStartedEvent = commandStartedEvent;
6064
this.requestContext = requestContext;
6165
this.collectionName = getCollectionName(commandStartedEvent);

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/MongoHandlerObservationConvention.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2022 the original author or authors.
2+
* Copyright 2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
2222
* {@link ObservationConvention} for {@link MongoHandlerContext}.
2323
*
2424
* @author Greg Turnquist
25-
* @since 4.0.0
25+
* @since 4
2626
*/
2727
public interface MongoHandlerObservationConvention extends ObservationConvention<MongoHandlerContext> {
2828

Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
package org.springframework.data.mongodb.observability;
22

3-
import io.micrometer.observation.ObservationRegistry;
4-
import io.micrometer.tracing.Tracer;
53
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
6+
import io.micrometer.observation.ObservationRegistry;
67

78
/**
89
* Class to configure needed beans for MongoDB + Micrometer.
10+
*
11+
* @since 3.0
912
*/
13+
@Configuration
1014
public class MongoMetricsConfiguration {
1115

12-
@Bean
13-
MongoObservationCommandListener mongoObservationCommandListener(ObservationRegistry registry) {
14-
return new MongoObservationCommandListener(registry);
15-
}
16+
@Bean
17+
public MongoObservationCommandListener mongoObservationCommandListener(ObservationRegistry registry) {
18+
return new MongoObservationCommandListener(registry);
19+
}
1620

17-
@Bean
18-
MongoTracingObservationHandler mongoTracingObservationHandler(Tracer tracer) {
19-
return new MongoTracingObservationHandler(tracer);
20-
}
2121
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/MongoMetricsConfigurationHelper.java

Lines changed: 0 additions & 21 deletions
This file was deleted.

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/MongoMetricsReactiveConfigurationHelper.java

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)