From 9f8a262e6bdfb75ea8b9a123ee3b7d25d7a672d9 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 14 Jun 2022 09:30:13 -0700 Subject: [PATCH] Log a warning when a health indicator takes too long to run Update `HealthEndpointSupport` so that it logs a warning if a health indicator takes too long to respond. Fixes gh-31231 --- .../health/HealthEndpointConfiguration.java | 7 ++-- .../health/HealthEndpointProperties.java | 29 +++++++++++++- ...ointReactiveWebExtensionConfiguration.java | 6 ++- ...althEndpointWebExtensionConfiguration.java | 5 ++- ...loudFoundryWebEndpointDiscovererTests.java | 4 +- .../HealthEndpointDocumentationTests.java | 4 +- .../boot/actuate/health/HealthEndpoint.java | 20 +++++++++- .../actuate/health/HealthEndpointSupport.java | 40 +++++++++++++++++-- .../health/HealthEndpointWebExtension.java | 20 +++++++++- .../ReactiveHealthEndpointWebExtension.java | 20 +++++++++- .../health/HealthEndpointSupportTests.java | 12 ++++-- .../actuate/health/HealthEndpointTests.java | 33 ++++++++++++--- .../HealthEndpointWebExtensionTests.java | 12 +++--- .../HealthEndpointWebIntegrationTests.java | 9 +++-- ...activeHealthEndpointWebExtensionTests.java | 9 +++-- .../src/docs/asciidoc/actuator/endpoints.adoc | 4 ++ 16 files changed, 192 insertions(+), 42 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java index 0190380e57fd..a63d67739e34 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -88,8 +88,9 @@ HealthContributorRegistry healthContributorRegistry(ApplicationContext applicati @Bean @ConditionalOnMissingBean - HealthEndpoint healthEndpoint(HealthContributorRegistry registry, HealthEndpointGroups groups) { - return new HealthEndpoint(registry, groups); + HealthEndpoint healthEndpoint(HealthContributorRegistry registry, HealthEndpointGroups groups, + HealthEndpointProperties properties) { + return new HealthEndpoint(registry, groups, properties.getLogging().getSlowIndicatorThreshold()); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointProperties.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointProperties.java index d536a89f8cb0..9b5466bfe89e 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointProperties.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.autoconfigure.health; +import java.time.Duration; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -43,6 +44,8 @@ public class HealthEndpointProperties extends HealthProperties { */ private Map group = new LinkedHashMap<>(); + private Logging logging = new Logging(); + @Override public Show getShowDetails() { return this.showDetails; @@ -56,6 +59,10 @@ public Map getGroup() { return this.group; } + public Logging getLogging() { + return this.logging; + } + /** * A health endpoint group. */ @@ -124,4 +131,24 @@ public void setAdditionalPath(String additionalPath) { } + /** + * Health logging properties. + */ + public static class Logging { + + /** + * Threshold after which a warning will be logged for slow health indicators. + */ + Duration slowIndicatorThreshold = Duration.ofSeconds(10); + + public Duration getSlowIndicatorThreshold() { + return this.slowIndicatorThreshold; + } + + public void setSlowIndicatorThreshold(Duration slowIndicatorThreshold) { + this.slowIndicatorThreshold = slowIndicatorThreshold; + } + + } + } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointReactiveWebExtensionConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointReactiveWebExtensionConfiguration.java index 462047629954..792c9d0f7e44 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointReactiveWebExtensionConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointReactiveWebExtensionConfiguration.java @@ -53,8 +53,10 @@ class HealthEndpointReactiveWebExtensionConfiguration { @ConditionalOnMissingBean @ConditionalOnBean(HealthEndpoint.class) ReactiveHealthEndpointWebExtension reactiveHealthEndpointWebExtension( - ReactiveHealthContributorRegistry reactiveHealthContributorRegistry, HealthEndpointGroups groups) { - return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry, groups); + ReactiveHealthContributorRegistry reactiveHealthContributorRegistry, HealthEndpointGroups groups, + HealthEndpointProperties properties) { + return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry, groups, + properties.getLogging().getSlowIndicatorThreshold()); } @Configuration(proxyBeanMethods = false) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java index 516fec82b6b9..857b6282959f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java @@ -72,8 +72,9 @@ class HealthEndpointWebExtensionConfiguration { @Bean @ConditionalOnMissingBean HealthEndpointWebExtension healthEndpointWebExtension(HealthContributorRegistry healthContributorRegistry, - HealthEndpointGroups groups) { - return new HealthEndpointWebExtension(healthContributorRegistry, groups); + HealthEndpointGroups groups, HealthEndpointProperties properties) { + return new HealthEndpointWebExtension(healthContributorRegistry, groups, + properties.getLogging().getSlowIndicatorThreshold()); } private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java index 84b9f4c62bf6..cf3a9494ceec 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryWebEndpointDiscovererTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-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. @@ -113,7 +113,7 @@ TestEndpointWebExtension testEndpointWebExtension() { HealthEndpoint healthEndpoint() { HealthContributorRegistry registry = mock(HealthContributorRegistry.class); HealthEndpointGroups groups = mock(HealthEndpointGroups.class); - return new HealthEndpoint(registry, groups); + return new HealthEndpoint(registry, groups, null); } @Bean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java index dae4df571097..a512ca7a1ba1 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/documentation/HealthEndpointDocumentationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -111,7 +111,7 @@ HealthEndpoint healthEndpoint(Map healthContributors) HealthContributorRegistry registry = new DefaultHealthContributorRegistry(healthContributors); HealthEndpointGroup primary = new TestHealthEndpointGroup(); HealthEndpointGroups groups = HealthEndpointGroups.of(primary, Collections.emptyMap()); - return new HealthEndpoint(registry, groups); + return new HealthEndpoint(registry, groups, null); } @Bean diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java index 4fcd7d4b7d34..d2f7eae830a8 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.health; +import java.time.Duration; import java.util.Map; import java.util.Set; @@ -51,9 +52,24 @@ public class HealthEndpoint extends HealthEndpointSupport { + private static final Log logger = LogFactory.getLog(HealthEndpointSupport.class); + static final Health DEFAULT_HEALTH = Health.up().build(); private final ContributorRegistry registry; private final HealthEndpointGroups groups; + private Duration slowIndicatorLoggingThreshold; + /** * Create a new {@link HealthEndpointSupport} instance. * @param registry the health contributor registry * @param groups the health endpoint groups + * @param slowIndicatorLoggingThreshold duration after which slow health indicator + * logging should occur */ - HealthEndpointSupport(ContributorRegistry registry, HealthEndpointGroups groups) { + HealthEndpointSupport(ContributorRegistry registry, HealthEndpointGroups groups, + Duration slowIndicatorLoggingThreshold) { Assert.notNull(registry, "Registry must not be null"); Assert.notNull(groups, "Groups must not be null"); this.registry = registry; this.groups = groups; + this.slowIndicatorLoggingThreshold = slowIndicatorLoggingThreshold; } HealthResult getHealth(ApiVersion apiVersion, WebServerNamespace serverNamespace, @@ -127,7 +142,7 @@ private T getContribution(ApiVersion apiVersion, HealthEndpointGroup group, Stri showDetails, groupNames); } if (contributor != null && (name.isEmpty() || group.isMember(name))) { - return getHealth((C) contributor, showDetails); + return getLoggedHealth((C) contributor, name, showDetails); } return null; } @@ -151,6 +166,25 @@ private T getAggregateContribution(ApiVersion apiVersion, HealthEndpointGroup gr groupNames); } + private T getLoggedHealth(C contributor, String name, boolean showDetails) { + Instant start = Instant.now(); + try { + return getHealth(contributor, showDetails); + } + finally { + if (logger.isWarnEnabled() && this.slowIndicatorLoggingThreshold != null) { + Duration duration = Duration.between(start, Instant.now()); + if (duration.compareTo(this.slowIndicatorLoggingThreshold) > 0) { + String contributorClassName = contributor.getClass().getName(); + Object contributorIdentifier = (!StringUtils.hasLength(name)) ? contributorClassName + : contributor.getClass().getName() + " (" + name + ")"; + logger.warn(LogMessage.format("Health contributor %s took %s to respond", contributorIdentifier, + DurationStyle.SIMPLE.print(duration))); + } + } + } + } + protected abstract T getHealth(C contributor, boolean includeDetails); protected abstract T aggregateContributions(ApiVersion apiVersion, Map contributions, diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java index 3c44d51137cd..b96f3c07acde 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpointWebExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.health; +import java.time.Duration; import java.util.Arrays; import java.util.Map; import java.util.Set; @@ -51,9 +52,24 @@ public class HealthEndpointWebExtension extends HealthEndpointSupport the support type * @param the registry type * @param the contributor type * @param the contributed health component type * @author Phillip Webb * @author Madhura Bhave */ -abstract class HealthEndpointSupportTests, C, T> { +abstract class HealthEndpointSupportTests, R extends ContributorRegistry, C, T> { final R registry; @@ -352,7 +354,11 @@ void getComponentHealthWhenGroupHasAdditionalPathAndShowComponentsFalse() { assertThat(result).isEqualTo(null); } - protected abstract HealthEndpointSupport create(R registry, HealthEndpointGroups groups); + protected final S create(R registry, HealthEndpointGroups groups) { + return create(registry, groups, null); + } + + protected abstract S create(R registry, HealthEndpointGroups groups, Duration slowIndicatorLoggingThreshold); protected abstract R createRegistry(); diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java index 776d29c83f31..02d20a5955b4 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-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. @@ -16,12 +16,16 @@ package org.springframework.boot.actuate.health; +import java.time.Duration; import java.util.Collections; import java.util.Map; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.actuate.health.HealthEndpointSupport.HealthResult; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -32,8 +36,9 @@ * @author Phillip Webb * @author Scott Frederick */ -class HealthEndpointTests - extends HealthEndpointSupportTests { +@ExtendWith(OutputCaptureExtension.class) +class HealthEndpointTests extends + HealthEndpointSupportTests { @Test void healthReturnsSystemHealth() { @@ -66,9 +71,27 @@ void healthWhenPathExistsReturnsHealth() { assertThat(health).isEqualTo(this.up); } + @Test + void healthWhenIndicatorIsSlow(CapturedOutput output) { + HealthIndicator indicator = () -> { + try { + Thread.sleep(100); + } + catch (InterruptedException ex) { + } + return this.up; + }; + this.registry.registerContributor("test", indicator); + create(this.registry, this.groups, Duration.ofMillis(10)).health(); + assertThat(output).contains("Health contributor"); + assertThat(output).contains("to respond"); + + } + @Override - protected HealthEndpoint create(HealthContributorRegistry registry, HealthEndpointGroups groups) { - return new HealthEndpoint(registry, groups); + protected HealthEndpoint create(HealthContributorRegistry registry, HealthEndpointGroups groups, + Duration slowIndicatorLoggingThreshold) { + return new HealthEndpoint(registry, groups, slowIndicatorLoggingThreshold); } @Override diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionTests.java index 778b2592f886..56f44169ce0d 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebExtensionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.health; +import java.time.Duration; import java.util.Collections; import java.util.Map; @@ -36,8 +37,8 @@ * @author Phillip Webb * @author Scott Frederick */ -class HealthEndpointWebExtensionTests - extends HealthEndpointSupportTests { +class HealthEndpointWebExtensionTests extends + HealthEndpointSupportTests { @Test void healthReturnsSystemHealth() { @@ -81,8 +82,9 @@ void healthWhenPathExistsReturnsHealth() { } @Override - protected HealthEndpointWebExtension create(HealthContributorRegistry registry, HealthEndpointGroups groups) { - return new HealthEndpointWebExtension(registry, groups); + protected HealthEndpointWebExtension create(HealthContributorRegistry registry, HealthEndpointGroups groups, + Duration slowIndicatorLoggingThreshold) { + return new HealthEndpointWebExtension(registry, groups, slowIndicatorLoggingThreshold); } @Override diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java index ab6c24431eb9..4db81a4971bd 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/HealthEndpointWebIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -188,14 +188,14 @@ ReactiveHealthContributorRegistry reactiveHealthContributorRegistry( @Bean HealthEndpoint healthEndpoint(HealthContributorRegistry healthContributorRegistry, HealthEndpointGroups healthEndpointGroups) { - return new HealthEndpoint(healthContributorRegistry, healthEndpointGroups); + return new HealthEndpoint(healthContributorRegistry, healthEndpointGroups, null); } @Bean @ConditionalOnWebApplication(type = Type.SERVLET) HealthEndpointWebExtension healthWebEndpointExtension(HealthContributorRegistry healthContributorRegistry, HealthEndpointGroups healthEndpointGroups) { - return new HealthEndpointWebExtension(healthContributorRegistry, healthEndpointGroups); + return new HealthEndpointWebExtension(healthContributorRegistry, healthEndpointGroups, null); } @Bean @@ -203,7 +203,8 @@ HealthEndpointWebExtension healthWebEndpointExtension(HealthContributorRegistry ReactiveHealthEndpointWebExtension reactiveHealthWebEndpointExtension( ReactiveHealthContributorRegistry reactiveHealthContributorRegistry, HealthEndpointGroups healthEndpointGroups) { - return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry, healthEndpointGroups); + return new ReactiveHealthEndpointWebExtension(reactiveHealthContributorRegistry, healthEndpointGroups, + null); } @Bean diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthEndpointWebExtensionTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthEndpointWebExtensionTests.java index 38acbd1acee9..92c7e0066546 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthEndpointWebExtensionTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/health/ReactiveHealthEndpointWebExtensionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-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. @@ -16,6 +16,7 @@ package org.springframework.boot.actuate.health; +import java.time.Duration; import java.util.Collections; import java.util.Map; @@ -37,7 +38,7 @@ * @author Scott Frederick */ class ReactiveHealthEndpointWebExtensionTests extends - HealthEndpointSupportTests> { + HealthEndpointSupportTests> { @Test void healthReturnsSystemHealth() { @@ -82,8 +83,8 @@ void healthWhenPathExistsReturnsHealth() { @Override protected ReactiveHealthEndpointWebExtension create(ReactiveHealthContributorRegistry registry, - HealthEndpointGroups groups) { - return new ReactiveHealthEndpointWebExtension(registry, groups); + HealthEndpointGroups groups, Duration slowIndicatorLoggingThreshold) { + return new ReactiveHealthEndpointWebExtension(registry, groups, slowIndicatorLoggingThreshold); } @Override diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc index f79536774c67..acd022903664 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc @@ -767,6 +767,10 @@ include::{docs-java}/actuator/endpoints/health/writingcustomhealthindicators/MyH NOTE: The identifier for a given `HealthIndicator` is the name of the bean without the `HealthIndicator` suffix, if it exists. In the preceding example, the health information is available in an entry named `my`. +TIP: Health indicators are usually called over HTTP and need to respond before any connection timeouts. +Spring Boot will log a warning message for any health indicator that takes longer than 10 seconds to respond. +If you want to configure this threshold, you can use the configprop:management.endpoint.health.logging.slow-indicator-threshold[] property + In addition to Spring Boot's predefined {spring-boot-actuator-module-code}/health/Status.java[`Status`] types, `Health` can return a custom `Status` that represents a new system state. In such cases, you also need to provide a custom implementation of the {spring-boot-actuator-module-code}/health/StatusAggregator.java[`StatusAggregator`] interface, or you must configure the default implementation by using the configprop:management.endpoint.health.status.order[] configuration property.