Browse Source

Polishing.

Update javadoc and connection string rendering.
pull/5052/head
Christoph Strobl 4 months ago
parent
commit
d4c97fc5bb
No known key found for this signature in database
GPG Key ID: E6054036D0C37A4B
  1. 5
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/MongoKeyName.java
  2. 56
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/MongoObservation.java
  3. 17
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/observability/Observer.java
  4. 66
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/observability/MongoObservationUnitTests.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2025 the original author or authors.
* Copyright 2025-present 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.
@ -30,6 +30,7 @@ import org.springframework.util.StringUtils; @@ -30,6 +30,7 @@ import org.springframework.util.StringUtils;
* {@link KeyValue} and {@link KeyName}.
*
* @author Mark Paluch
* @since 4.4.9
*/
record MongoKeyName<C>(String name, boolean required, Function<C, Object> valueFunction) implements KeyName {
@ -43,7 +44,7 @@ record MongoKeyName<C>(String name, boolean required, Function<C, Object> valueF @@ -43,7 +44,7 @@ record MongoKeyName<C>(String name, boolean required, Function<C, Object> valueF
* @return
* @param <C>
*/
public static <C> MongoKeyName<C> required(String name, Function<C, Object> valueFunction) {
static <C> MongoKeyName<C> required(String name, Function<C, Object> valueFunction) {
return required(name, valueFunction, Objects::nonNull);
}

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

@ -15,11 +15,17 @@ @@ -15,11 +15,17 @@
*/
package org.springframework.data.mongodb.observability;
import static org.springframework.data.mongodb.observability.MongoKeyName.*;
import static org.springframework.data.mongodb.observability.MongoKeyName.MongoKeyValue;
import static org.springframework.data.mongodb.observability.MongoKeyName.just;
import io.micrometer.common.docs.KeyName;
import io.micrometer.observation.docs.ObservationDocumentation;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
import org.springframework.lang.Contract;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
@ -86,7 +92,7 @@ enum MongoObservation implements ObservationDocumentation { @@ -86,7 +92,7 @@ enum MongoObservation implements ObservationDocumentation {
static MongoKeyName<ServerAddress> NET_PEER_PORT = MongoKeyName.required("net.peer.port", ServerAddress::getPort);
static MongoKeyName<ConnectionString> DB_CONNECTION_STRING = MongoKeyName.requiredString("db.connection_string",
Object::toString);
MongoObservation::connectionString);
static MongoKeyName<ConnectionString> DB_USER = MongoKeyName.requiredString("db.user",
ConnectionString::getUsername);
@ -96,7 +102,7 @@ enum MongoObservation implements ObservationDocumentation { @@ -96,7 +102,7 @@ enum MongoObservation implements ObservationDocumentation {
* @param context the context to contribute from, can be {@literal null} if no context is available.
* @return the key value contributor providing low cardinality key names.
*/
public static Observer observe(@Nullable MongoHandlerContext context) {
static Observer observe(@Nullable MongoHandlerContext context) {
return Observer.fromContext(context, it -> {
@ -115,9 +121,51 @@ enum MongoObservation implements ObservationDocumentation { @@ -115,9 +121,51 @@ enum MongoObservation implements ObservationDocumentation {
*
* @return the key names for low cardinality keys.
*/
public static KeyName[] getKeyNames() {
static KeyName[] getKeyNames() {
return observe(null).toKeyNames();
}
}
@Contract("null -> null")
static @Nullable String connectionString(@Nullable ConnectionString connectionString) {
if (connectionString == null) {
return null;
}
if (!StringUtils.hasText(connectionString.getUsername()) && connectionString.getPassword() == null) {
return connectionString.toString();
}
String target = renderPart(connectionString.toString(), "//", connectionString.getUsername());
if (connectionString.getPassword() != null) {
String rendered = renderPart(target, ":", new String(connectionString.getPassword()));
if (!rendered.equals(target)) {
target = rendered;
} else {
String protocol = connectionString.isSrvProtocol() ? "mongodb+srv" : "mongodb";
target = "%s://*****:*****@%s".formatted(protocol,
StringUtils.collectionToCommaDelimitedString(connectionString.getHosts()));
}
}
return target;
}
private static String renderPart(String source, String prefix, @Nullable String part) {
if (!StringUtils.hasText(part)) {
return source;
}
String intermediate = source.replaceFirst(prefix + Pattern.quote(part), "%s*****".formatted(prefix));
if (!intermediate.equals(source)) {
return intermediate;
}
String encoded = URLEncoder.encode(part, StandardCharsets.UTF_8);
return source.replaceFirst(prefix + Pattern.quote(encoded), "%s*****".formatted(prefix));
}
}

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

@ -30,6 +30,7 @@ import org.springframework.lang.Nullable; @@ -30,6 +30,7 @@ import org.springframework.lang.Nullable;
* observability systems.
*
* @author Mark Paluch
* @since 4.4.9
*/
class Observer {
@ -40,7 +41,7 @@ class Observer { @@ -40,7 +41,7 @@ class Observer {
*
* @return a new {@link Observer}.
*/
public static Observer create() {
static Observer create() {
return new Observer();
}
@ -53,7 +54,7 @@ class Observer { @@ -53,7 +54,7 @@ class Observer {
* @return the stateful {@link Observer}.
* @param <C> context type.
*/
public static <C> Observer fromContext(@Nullable C context, Consumer<? super ContextualObserver<C>> consumer) {
static <C> Observer fromContext(@Nullable C context, Consumer<? super ContextualObserver<C>> consumer) {
Observer contributor = create();
@ -68,7 +69,7 @@ class Observer { @@ -68,7 +69,7 @@ class Observer {
* @param keyValue
* @return
*/
public Observer contribute(MongoKeyName.MongoKeyValue keyValue) {
Observer contribute(MongoKeyName.MongoKeyValue keyValue) {
keyValues.add(keyValue);
@ -83,7 +84,7 @@ class Observer { @@ -83,7 +84,7 @@ class Observer {
* @return the nested contextual {@link ContextualObserver} that can contribute key-value tuples.
* @param <C>
*/
public <C> ContextualObserver<C> contextual(@Nullable C context) {
<C> ContextualObserver<C> contextual(@Nullable C context) {
if (context == null) {
return new EmptyContextualObserver<>(keyValues);
@ -92,15 +93,11 @@ class Observer { @@ -92,15 +93,11 @@ class Observer {
return new DefaultContextualObserver<>(context, keyValues);
}
public <T> ContextualObserver<T> empty(Class<T> targetType) {
return new EmptyContextualObserver<>(this.keyValues);
}
public KeyValues toKeyValues() {
KeyValues toKeyValues() {
return KeyValues.of(keyValues);
}
public KeyName[] toKeyNames() {
KeyName[] toKeyNames() {
KeyName[] keyNames = new KeyName[keyValues.size()];

66
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/observability/MongoObservationUnitTests.java

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
/*
* Copyright 2025-present 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 static org.assertj.core.api.Assertions.assertThat;
import java.nio.charset.StandardCharsets;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import com.mongodb.ConnectionString;
/**
* @author Christoph Strobl
*/
class MongoObservationUnitTests {
@ParameterizedTest // GH-5020
@MethodSource("connectionStrings")
void connectionStringRendering(ConnectionString source, String expected) {
assertThat(MongoObservation.connectionString(source)).isEqualTo(expected);
}
private static Stream<Arguments> connectionStrings() {
return Stream.of(Arguments.of(new ConnectionString(
"mongodb+srv://m0ngP%40oUser:m0ngP%40o@cluster0.example.mongodb.net/?retryWrites=true&w=majority"),
"mongodb+srv://*****:*****@cluster0.example.mongodb.net/?retryWrites=true&w=majority"), //
Arguments.of(new ConnectionString(
"mongodb://mongodb:m0ngP%40o@cluster0.example.mongodb.net,cluster1.example.com:1234/?retryWrites=true"),
"mongodb://*****:*****@cluster0.example.mongodb.net,cluster1.example.com:1234/?retryWrites=true"), //
Arguments.of(
new ConnectionString("mongodb://myDatabaseUser@cluster0.example.mongodb.net/?authMechanism=MONGODB-X509"),
"mongodb://*****@cluster0.example.mongodb.net/?authMechanism=MONGODB-X509"), //
Arguments.of(
new ConnectionString("mongodb+srv://myDatabaseUser:mongodb@cluster0.example.mongodb.net/?w=acknowledged"),
"mongodb+srv://*****:*****@cluster0.example.mongodb.net/?w=acknowledged"), //
Arguments.of(
new ConnectionString(
new String("mongodb://mongodb:mongodb@localhost:27017".getBytes(), StandardCharsets.US_ASCII)),
"mongodb://*****:*****@localhost:27017"),
Arguments.of(new ConnectionString("mongodb+srv://cluster0.example.mongodb.net/?retryWrites=true&w=majority"),
"mongodb+srv://cluster0.example.mongodb.net/?retryWrites=true&w=majority"), //
Arguments.of(
new ConnectionString(
"mongodb+srv://mongodb:mongodb@cluster0.example.mongodb.net/?retryWrites=true&w=majority"),
"mongodb+srv://*****:*****@cluster0.example.mongodb.net/?retryWrites=true&w=majority"));
}
}
Loading…
Cancel
Save