pull/28102/head
Phillip Webb 3 years ago
parent 98a0e07dd5
commit 667e5ca30c

@ -65,18 +65,38 @@ public class Sanitizer {
DEFAULT_KEYS_TO_SANITIZE.addAll(URI_USERINFO_KEYS); DEFAULT_KEYS_TO_SANITIZE.addAll(URI_USERINFO_KEYS);
} }
/**
* Create a new {@link Sanitizer} instance with a default set of keys to sanitize.
*/
public Sanitizer() { public Sanitizer() {
this(DEFAULT_KEYS_TO_SANITIZE.toArray(new String[0])); this(DEFAULT_KEYS_TO_SANITIZE.toArray(new String[0]));
} }
/**
* Create a new {@link Sanitizer} instance with specific keys to sanitize.
* @param keysToSanitize the keys to sanitize
*/
public Sanitizer(String... keysToSanitize) { public Sanitizer(String... keysToSanitize) {
this(Collections.emptyList(), keysToSanitize); this(Collections.emptyList(), keysToSanitize);
} }
/**
* Create a new {@link Sanitizer} instance with a default set of keys to sanitize and
* additional sanitizing functions.
* @param sanitizingFunctions the sanitizing functions to apply
* @since 2.6.0
*/
public Sanitizer(Iterable<SanitizingFunction> sanitizingFunctions) { public Sanitizer(Iterable<SanitizingFunction> sanitizingFunctions) {
this(sanitizingFunctions, DEFAULT_KEYS_TO_SANITIZE.toArray(new String[0])); this(sanitizingFunctions, DEFAULT_KEYS_TO_SANITIZE.toArray(new String[0]));
} }
/**
* Create a new {@link Sanitizer} instance with specific keys to sanitize and
* additional sanitizing functions.
* @param sanitizingFunctions the sanitizing functions to apply
* @param keysToSanitize the keys to sanitize
* @since 2.6.0
*/
public Sanitizer(Iterable<SanitizingFunction> sanitizingFunctions, String... keysToSanitize) { public Sanitizer(Iterable<SanitizingFunction> sanitizingFunctions, String... keysToSanitize) {
sanitizingFunctions.forEach(this.sanitizingFunctions::add); sanitizingFunctions.forEach(this.sanitizingFunctions::add);
this.sanitizingFunctions.add(getDefaultSanitizingFunction()); this.sanitizingFunctions.add(getDefaultSanitizingFunction());

@ -84,17 +84,13 @@ public abstract class AbstractHealthIndicator implements HealthIndicator {
catch (Exception ex) { catch (Exception ex) {
builder.down(ex); builder.down(ex);
} }
logExceptionIfPresent(builder); logExceptionIfPresent(builder.getException());
return builder.build(); return builder.build();
} }
private void logExceptionIfPresent(Builder builder) { private void logExceptionIfPresent(Throwable ex) {
Throwable ex = builder.getException();
if (ex != null && this.logger.isWarnEnabled()) { if (ex != null && this.logger.isWarnEnabled()) {
String message = null; String message = (ex instanceof Exception) ? this.healthCheckFailedMessage.apply((Exception) ex) : null;
if (ex instanceof Exception) {
message = this.healthCheckFailedMessage.apply((Exception) ex);
}
this.logger.warn(StringUtils.hasText(message) ? message : DEFAULT_MESSAGE, ex); this.logger.warn(StringUtils.hasText(message) ? message : DEFAULT_MESSAGE, ex);
} }
} }

@ -323,15 +323,6 @@ public final class Health extends HealthComponent {
return this; return this;
} }
/**
* Return the {@link Exception}.
* @return the exception or {@code null} if the builder has no exception
* @since 2.6.0
*/
public Throwable getException() {
return this.exception;
}
/** /**
* Create a new {@link Health} instance with the previously specified code and * Create a new {@link Health} instance with the previously specified code and
* details. * details.
@ -341,6 +332,14 @@ public final class Health extends HealthComponent {
return new Health(this); return new Health(this);
} }
/**
* Return the {@link Exception}.
* @return the exception or {@code null} if the builder has no exception
*/
Throwable getException() {
return this.exception;
}
} }
} }

@ -16,6 +16,8 @@
package org.springframework.boot.actuate.health; package org.springframework.boot.actuate.health;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -36,76 +38,78 @@ class AbstractHealthIndicatorTests {
@Test @Test
void healthCheckWhenUpDoesNotLogHealthCheckFailedMessage(CapturedOutput output) { void healthCheckWhenUpDoesNotLogHealthCheckFailedMessage(CapturedOutput output) {
Health heath = new AbstractHealthIndicator("Test message") { TestHealthIndicator indicator = new TestHealthIndicator("Test message", Builder::up);
@Override Health heath = indicator.health();
protected void doHealthCheck(Builder builder) {
builder.up();
}
}.health();
assertThat(heath.getStatus()).isEqualTo(Status.UP); assertThat(heath.getStatus()).isEqualTo(Status.UP);
assertThat(output).doesNotContain("Test message"); assertThat(output).doesNotContain("Test message");
} }
@Test @Test
void healthCheckWhenDownWithExceptionThrownDoesNotLogHealthCheckFailedMessage(CapturedOutput output) { void healthCheckWhenDownWithExceptionThrownDoesNotLogHealthCheckFailedMessage(CapturedOutput output) {
Health heath = new AbstractHealthIndicator("Test message") { TestHealthIndicator indicator = new TestHealthIndicator("Test message", (builder) -> {
@Override throw new IllegalStateException("Test exception");
protected void doHealthCheck(Builder builder) { });
throw new IllegalStateException("Test exception"); Health heath = indicator.health();
}
}.health();
assertThat(heath.getStatus()).isEqualTo(Status.DOWN); assertThat(heath.getStatus()).isEqualTo(Status.DOWN);
assertThat(output).contains("Test message").contains("Test exception"); assertThat(output).contains("Test message").contains("Test exception");
} }
@Test @Test
void healthCheckWhenDownWithExceptionConfiguredDoesNotLogHealthCheckFailedMessage(CapturedOutput output) { void healthCheckWhenDownWithExceptionConfiguredDoesNotLogHealthCheckFailedMessage(CapturedOutput output) {
Health heath = new AbstractHealthIndicator("Test message") { Health heath = new TestHealthIndicator("Test message",
@Override (builder) -> builder.down().withException(new IllegalStateException("Test exception"))).health();
protected void doHealthCheck(Builder builder) {
builder.down().withException(new IllegalStateException("Test exception"));
}
}.health();
assertThat(heath.getStatus()).isEqualTo(Status.DOWN); assertThat(heath.getStatus()).isEqualTo(Status.DOWN);
assertThat(output).contains("Test message").contains("Test exception"); assertThat(output).contains("Test message").contains("Test exception");
} }
@Test @Test
void healthCheckWhenDownWithExceptionConfiguredDoesNotLogHealthCheckFailedMessageTwice(CapturedOutput output) { void healthCheckWhenDownWithExceptionConfiguredDoesNotLogHealthCheckFailedMessageTwice(CapturedOutput output) {
Health heath = new AbstractHealthIndicator("Test message") { TestHealthIndicator indicator = new TestHealthIndicator("Test message", (builder) -> {
@Override IllegalStateException ex = new IllegalStateException("Test exception");
protected void doHealthCheck(Builder builder) { builder.down().withException(ex);
IllegalStateException ex = new IllegalStateException("Test exception"); throw ex;
builder.down().withException(ex); });
throw ex; Health heath = indicator.health();
}
}.health();
assertThat(heath.getStatus()).isEqualTo(Status.DOWN); assertThat(heath.getStatus()).isEqualTo(Status.DOWN);
assertThat(output).contains("Test message").containsOnlyOnce("Test exception"); assertThat(output).contains("Test message").containsOnlyOnce("Test exception");
} }
@Test @Test
void healthCheckWhenDownWithExceptionAndNoFailureMessageLogsDefaultMessage(CapturedOutput output) { void healthCheckWhenDownWithExceptionAndNoFailureMessageLogsDefaultMessage(CapturedOutput output) {
Health heath = new AbstractHealthIndicator() { TestHealthIndicator indicator = new TestHealthIndicator(
@Override (builder) -> builder.down().withException(new IllegalStateException("Test exception")));
protected void doHealthCheck(Builder builder) { Health heath = indicator.health();
builder.down().withException(new IllegalStateException("Test exception"));
}
}.health();
assertThat(heath.getStatus()).isEqualTo(Status.DOWN); assertThat(heath.getStatus()).isEqualTo(Status.DOWN);
assertThat(output).contains("Health check failed").contains("Test exception"); assertThat(output).contains("Health check failed").contains("Test exception");
} }
@Test @Test
void healthCheckWhenDownWithErrorLogsDefaultMessage(CapturedOutput output) { void healthCheckWhenDownWithErrorLogsDefaultMessage(CapturedOutput output) {
Health heath = new AbstractHealthIndicator("Test Message") { TestHealthIndicator indicator = new TestHealthIndicator("Test Message",
@Override (builder) -> builder.down().withException(new Error("Test error")));
protected void doHealthCheck(Builder builder) { Health heath = indicator.health();
builder.down().withException(new Error("Test error"));
}
}.health();
assertThat(heath.getStatus()).isEqualTo(Status.DOWN); assertThat(heath.getStatus()).isEqualTo(Status.DOWN);
assertThat(output).contains("Health check failed").contains("Test error"); assertThat(output).contains("Health check failed").contains("Test error");
} }
static class TestHealthIndicator extends AbstractHealthIndicator {
private Consumer<Builder> action;
TestHealthIndicator(String message, Consumer<Builder> action) {
super(message);
this.action = action;
}
TestHealthIndicator(Consumer<Builder> action) {
this.action = action;
}
@Override
protected void doHealthCheck(Builder builder) throws Exception {
this.action.accept(builder);
}
}
} }

@ -37,6 +37,7 @@ import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsea
import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients; import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients;
import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients.WebClientConfigurationCallback; import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients.WebClientConfigurationCallback;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.unit.DataSize; import org.springframework.util.unit.DataSize;
import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
@ -120,7 +121,11 @@ public class ReactiveElasticsearchRestClientAutoConfiguration {
if (this.deprecatedProperties.isCustomized()) { if (this.deprecatedProperties.isCustomized()) {
return this.deprecatedProperties.getEndpoints(); return this.deprecatedProperties.getEndpoints();
} }
return this.uris.stream().map((uri) -> uri.getHost() + ":" + uri.getPort()).collect(Collectors.toList()); return this.uris.stream().map(this::getEndpoint).collect(Collectors.toList());
}
private String getEndpoint(URI uri) {
return uri.getHost() + ":" + uri.getPort();
} }
private Credentials getCredentials() { private Credentials getCredentials() {
@ -132,13 +137,10 @@ public class ReactiveElasticsearchRestClientAutoConfiguration {
if (uriCredentials == null) { if (uriCredentials == null) {
return propertyCredentials; return propertyCredentials;
} }
if (propertyCredentials != null && !uriCredentials.equals(propertyCredentials)) { Assert.isTrue(propertyCredentials == null || uriCredentials.equals(propertyCredentials),
throw new IllegalArgumentException( "Credentials from URI user info do not match those from spring.elasticsearch.username and "
"Credentials from URI user info do not match those from spring.elasticsearch.username and " + "spring.elasticsearch.password");
+ "spring.elasticsearch.password");
}
return uriCredentials; return uriCredentials;
} }
private Duration getConnectionTimeout() { private Duration getConnectionTimeout() {
@ -155,8 +157,8 @@ public class ReactiveElasticsearchRestClientAutoConfiguration {
if (this.deprecatedProperties.isCustomized()) { if (this.deprecatedProperties.isCustomized()) {
return this.deprecatedProperties.isUseSsl(); return this.deprecatedProperties.isUseSsl();
} }
Set<String> schemes = this.uris.stream().map((uri) -> uri.getScheme()).collect(Collectors.toSet()); Set<String> schemes = this.uris.stream().map(URI::getScheme).collect(Collectors.toSet());
Assert.isTrue(schemes.size() == 1, () -> "Configured Elasticsearch URIs have varying schemes"); Assert.isTrue(schemes.size() == 1, "Configured Elasticsearch URIs have varying schemes");
return schemes.iterator().next().equals("https"); return schemes.iterator().next().equals("https");
} }
@ -189,29 +191,28 @@ public class ReactiveElasticsearchRestClientAutoConfiguration {
} }
private static Credentials from(List<String> uris) { private static Credentials from(List<String> uris) {
Set<String> userInfos = uris.stream().map(URI::create).map((uri) -> uri.getUserInfo()) Set<String> userInfos = uris.stream().map(URI::create).map(URI::getUserInfo)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Assert.isTrue(userInfos.size() == 1, () -> "Configured Elasticsearch URIs have varying user infos"); Assert.isTrue(userInfos.size() == 1, "Configured Elasticsearch URIs have varying user infos");
String userInfo = userInfos.iterator().next(); String userInfo = userInfos.iterator().next();
if (userInfo != null) { if (userInfo == null) {
String[] parts = userInfo.split(":"); return null;
return new Credentials(parts[0], (parts.length == 2) ? parts[1] : "");
} }
return null; String[] parts = userInfo.split(":");
String username = parts[0];
String password = (parts.length != 2) ? "" : parts[1];
return new Credentials(username, password);
} }
private static Credentials from(ElasticsearchProperties properties) { private static Credentials from(ElasticsearchProperties properties) {
String username = properties.getUsername(); return getCredentials(properties.getUsername(), properties.getPassword());
String password = properties.getPassword();
if (username == null && password == null) {
return null;
}
return new Credentials(username, password);
} }
private static Credentials from(DeprecatedReactiveElasticsearchRestClientProperties properties) { private static Credentials from(DeprecatedReactiveElasticsearchRestClientProperties properties) {
String username = properties.getUsername(); return getCredentials(properties.getUsername(), properties.getPassword());
String password = properties.getPassword(); }
private static Credentials getCredentials(String username, String password) {
if (username == null && password == null) { if (username == null && password == null) {
return null; return null;
} }
@ -223,38 +224,20 @@ public class ReactiveElasticsearchRestClientAutoConfiguration {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj == null) { if (obj == null || getClass() != obj.getClass()) {
return false;
}
if (getClass() != obj.getClass()) {
return false; return false;
} }
Credentials other = (Credentials) obj; Credentials other = (Credentials) obj;
if (this.password == null) { return ObjectUtils.nullSafeEquals(this.username, other.username)
if (other.password != null) { && ObjectUtils.nullSafeEquals(this.password, other.password);
return false;
}
}
else if (!this.password.equals(other.password)) {
return false;
}
if (this.username == null) {
if (other.username != null) {
return false;
}
}
else if (!this.username.equals(other.username)) {
return false;
}
return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + ((this.password == null) ? 0 : this.password.hashCode()); result = prime * result + ObjectUtils.nullSafeHashCode(this.username);
result = prime * result + ((this.username == null) ? 0 : this.username.hashCode()); result = prime * result + ObjectUtils.nullSafeHashCode(this.password);
return result; return result;
} }

@ -1081,7 +1081,6 @@ Long task timers require a separate metric name and can be stacked with a short
[[actuator.metrics.supported.redis]] [[actuator.metrics.supported.redis]]
==== Redis Metrics ==== Redis Metrics
Auto-configuration registers a `MicrometerCommandLatencyRecorder` for the auto-configured `LettuceConnectionFactory`. Auto-configuration registers a `MicrometerCommandLatencyRecorder` for the auto-configured `LettuceConnectionFactory`.
For more details refer to the {lettuce-docs}#command.latency.metrics.micrometer[Micrometer Metrics section] of the Lettuce documentation. For more details refer to the {lettuce-docs}#command.latency.metrics.micrometer[Micrometer Metrics section] of the Lettuce documentation.

Loading…
Cancel
Save