Skip to content

Commit b5664de

Browse files
Polishing.
Update javadoc and connection string rendering.
1 parent 066ec50 commit b5664de

File tree

4 files changed

+128
-16
lines changed

4 files changed

+128
-16
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2025 the original author or authors.
2+
* Copyright 2025-present 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.
@@ -30,6 +30,7 @@
3030
* {@link KeyValue} and {@link KeyName}.
3131
*
3232
* @author Mark Paluch
33+
* @since 4.4.9
3334
*/
3435
record MongoKeyName<C>(String name, boolean required, Function<C, Object> valueFunction) implements KeyName {
3536

@@ -43,7 +44,7 @@ record MongoKeyName<C>(String name, boolean required, Function<C, Object> valueF
4344
* @return
4445
* @param <C>
4546
*/
46-
public static <C> MongoKeyName<C> required(String name, Function<C, Object> valueFunction) {
47+
static <C> MongoKeyName<C> required(String name, Function<C, Object> valueFunction) {
4748
return required(name, valueFunction, Objects::nonNull);
4849
}
4950

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

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@
1515
*/
1616
package org.springframework.data.mongodb.observability;
1717

18-
import static org.springframework.data.mongodb.observability.MongoKeyName.*;
18+
import static org.springframework.data.mongodb.observability.MongoKeyName.MongoKeyValue;
19+
import static org.springframework.data.mongodb.observability.MongoKeyName.just;
1920

2021
import io.micrometer.common.docs.KeyName;
2122
import io.micrometer.observation.docs.ObservationDocumentation;
2223

24+
import java.net.URLEncoder;
25+
import java.nio.charset.StandardCharsets;
26+
import java.util.regex.Pattern;
27+
28+
import org.springframework.lang.Contract;
2329
import org.springframework.lang.Nullable;
2430
import org.springframework.util.StringUtils;
2531

@@ -86,7 +92,7 @@ static class LowCardinality {
8692
static MongoKeyName<ServerAddress> NET_PEER_PORT = MongoKeyName.required("net.peer.port", ServerAddress::getPort);
8793

8894
static MongoKeyName<ConnectionString> DB_CONNECTION_STRING = MongoKeyName.requiredString("db.connection_string",
89-
Object::toString);
95+
MongoObservation::connectionString);
9096
static MongoKeyName<ConnectionString> DB_USER = MongoKeyName.requiredString("db.user",
9197
ConnectionString::getUsername);
9298

@@ -96,7 +102,7 @@ static class LowCardinality {
96102
* @param context the context to contribute from, can be {@literal null} if no context is available.
97103
* @return the key value contributor providing low cardinality key names.
98104
*/
99-
public static Observer observe(@Nullable MongoHandlerContext context) {
105+
static Observer observe(@Nullable MongoHandlerContext context) {
100106

101107
return Observer.fromContext(context, it -> {
102108

@@ -115,9 +121,51 @@ public static Observer observe(@Nullable MongoHandlerContext context) {
115121
*
116122
* @return the key names for low cardinality keys.
117123
*/
118-
public static KeyName[] getKeyNames() {
124+
static KeyName[] getKeyNames() {
119125
return observe(null).toKeyNames();
120126
}
121127
}
122128

129+
@Contract("null -> null")
130+
static @Nullable String connectionString(@Nullable ConnectionString connectionString) {
131+
132+
if (connectionString == null) {
133+
return null;
134+
}
135+
136+
if (!StringUtils.hasText(connectionString.getUsername()) && connectionString.getPassword() == null) {
137+
return connectionString.toString();
138+
}
139+
140+
String target = renderPart(connectionString.toString(), "//", connectionString.getUsername());
141+
142+
if (connectionString.getPassword() != null) {
143+
144+
String rendered = renderPart(target, ":", new String(connectionString.getPassword()));
145+
if (!rendered.equals(target)) {
146+
target = rendered;
147+
} else {
148+
String protocol = connectionString.isSrvProtocol() ? "mongodb+srv" : "mongodb";
149+
target = "%s://*****:*****@%s".formatted(protocol,
150+
StringUtils.collectionToCommaDelimitedString(connectionString.getHosts()));
151+
}
152+
}
153+
154+
return target;
155+
}
156+
157+
private static String renderPart(String source, String prefix, @Nullable String part) {
158+
159+
if (!StringUtils.hasText(part)) {
160+
return source;
161+
}
162+
163+
String intermediate = source.replaceFirst(prefix + Pattern.quote(part), "%s*****".formatted(prefix));
164+
if (!intermediate.equals(source)) {
165+
return intermediate;
166+
}
167+
168+
String encoded = URLEncoder.encode(part, StandardCharsets.UTF_8);
169+
return source.replaceFirst(prefix + Pattern.quote(encoded), "%s*****".formatted(prefix));
170+
}
123171
}

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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* observability systems.
3131
*
3232
* @author Mark Paluch
33+
* @since 4.4.9
3334
*/
3435
class Observer {
3536

@@ -40,7 +41,7 @@ class Observer {
4041
*
4142
* @return a new {@link Observer}.
4243
*/
43-
public static Observer create() {
44+
static Observer create() {
4445
return new Observer();
4546
}
4647

@@ -53,7 +54,7 @@ public static Observer create() {
5354
* @return the stateful {@link Observer}.
5455
* @param <C> context type.
5556
*/
56-
public static <C> Observer fromContext(@Nullable C context, Consumer<? super ContextualObserver<C>> consumer) {
57+
static <C> Observer fromContext(@Nullable C context, Consumer<? super ContextualObserver<C>> consumer) {
5758

5859
Observer contributor = create();
5960

@@ -68,7 +69,7 @@ public static <C> Observer fromContext(@Nullable C context, Consumer<? super Con
6869
* @param keyValue
6970
* @return
7071
*/
71-
public Observer contribute(MongoKeyName.MongoKeyValue keyValue) {
72+
Observer contribute(MongoKeyName.MongoKeyValue keyValue) {
7273

7374
keyValues.add(keyValue);
7475

@@ -83,7 +84,7 @@ public Observer contribute(MongoKeyName.MongoKeyValue keyValue) {
8384
* @return the nested contextual {@link ContextualObserver} that can contribute key-value tuples.
8485
* @param <C>
8586
*/
86-
public <C> ContextualObserver<C> contextual(@Nullable C context) {
87+
<C> ContextualObserver<C> contextual(@Nullable C context) {
8788

8889
if (context == null) {
8990
return new EmptyContextualObserver<>(keyValues);
@@ -92,15 +93,11 @@ public <C> ContextualObserver<C> contextual(@Nullable C context) {
9293
return new DefaultContextualObserver<>(context, keyValues);
9394
}
9495

95-
public <T> ContextualObserver<T> empty(Class<T> targetType) {
96-
return new EmptyContextualObserver<>(this.keyValues);
97-
}
98-
99-
public KeyValues toKeyValues() {
96+
KeyValues toKeyValues() {
10097
return KeyValues.of(keyValues);
10198
}
10299

103-
public KeyName[] toKeyNames() {
100+
KeyName[] toKeyNames() {
104101

105102
KeyName[] keyNames = new KeyName[keyValues.size()];
106103

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2025-present 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 static org.assertj.core.api.Assertions.assertThat;
19+
20+
import java.nio.charset.StandardCharsets;
21+
import java.util.stream.Stream;
22+
23+
import org.junit.jupiter.params.ParameterizedTest;
24+
import org.junit.jupiter.params.provider.Arguments;
25+
import org.junit.jupiter.params.provider.MethodSource;
26+
27+
import com.mongodb.ConnectionString;
28+
29+
/**
30+
* @author Christoph Strobl
31+
*/
32+
class MongoObservationUnitTests {
33+
34+
@ParameterizedTest // GH-5020
35+
@MethodSource("connectionStrings")
36+
void connectionStringRendering(ConnectionString source, String expected) {
37+
assertThat(MongoObservation.connectionString(source)).isEqualTo(expected);
38+
}
39+
40+
private static Stream<Arguments> connectionStrings() {
41+
42+
return Stream.of(Arguments.of(new ConnectionString(
43+
"mongodb+srv://m0ngP%40oUser:m0ngP%[email protected]/?retryWrites=true&w=majority"),
44+
"mongodb+srv://*****:*****@cluster0.example.mongodb.net/?retryWrites=true&w=majority"), //
45+
Arguments.of(new ConnectionString(
46+
"mongodb://mongodb:m0ngP%[email protected],cluster1.example.com:1234/?retryWrites=true"),
47+
"mongodb://*****:*****@cluster0.example.mongodb.net,cluster1.example.com:1234/?retryWrites=true"), //
48+
Arguments.of(
49+
new ConnectionString("mongodb://[email protected]/?authMechanism=MONGODB-X509"),
50+
"mongodb://*****@cluster0.example.mongodb.net/?authMechanism=MONGODB-X509"), //
51+
Arguments.of(
52+
new ConnectionString("mongodb+srv://myDatabaseUser:[email protected]/?w=acknowledged"),
53+
"mongodb+srv://*****:*****@cluster0.example.mongodb.net/?w=acknowledged"), //
54+
Arguments.of(
55+
new ConnectionString(
56+
new String("mongodb://mongodb:mongodb@localhost:27017".getBytes(), StandardCharsets.US_ASCII)),
57+
"mongodb://*****:*****@localhost:27017"),
58+
Arguments.of(new ConnectionString("mongodb+srv://cluster0.example.mongodb.net/?retryWrites=true&w=majority"),
59+
"mongodb+srv://cluster0.example.mongodb.net/?retryWrites=true&w=majority"), //
60+
Arguments.of(
61+
new ConnectionString(
62+
"mongodb+srv://mongodb:[email protected]/?retryWrites=true&w=majority"),
63+
"mongodb+srv://*****:*****@cluster0.example.mongodb.net/?retryWrites=true&w=majority"));
64+
}
65+
66+
}

0 commit comments

Comments
 (0)