diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
index baa1dba33..71862fe26 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-core-example/src/main/resources/application.properties
@@ -1,6 +1,8 @@
spring.application.name=sentinel-example
server.port=18083
management.endpoints.web.exposure.include=*
+management.endpoint.health.show-details=always
+
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
@@ -19,4 +21,4 @@ spring.cloud.sentinel.datasource.ds4.file.file=classpath: system.json
spring.cloud.sentinel.datasource.ds4.file.rule-type=system
spring.cloud.sentinel.datasource.ds5.file.file=classpath: param-flow.json
-spring.cloud.sentinel.datasource.ds5.file.rule-type=param-flow
+spring.cloud.sentinel.datasource.ds5.file.rule-type=param_flow
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
index 7c9b5d1c5..7388147a9 100644
--- a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelEndpointAutoConfiguration.java
@@ -17,6 +17,7 @@
package org.springframework.cloud.alibaba.sentinel.endpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
+import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -38,4 +39,10 @@ public class SentinelEndpointAutoConfiguration {
return new SentinelEndpoint(sentinelProperties);
}
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnEnabledHealthIndicator("sentinel")
+ public SentinelHealthIndicator sentinelHealthIndicator(SentinelProperties sentinelProperties) {
+ return new SentinelHealthIndicator(sentinelProperties);
+ }
}
diff --git a/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
new file mode 100644
index 000000000..821021006
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/main/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicator.java
@@ -0,0 +1,67 @@
+package org.springframework.cloud.alibaba.sentinel.endpoint;
+
+import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
+import com.alibaba.csp.sentinel.transport.HeartbeatSender;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+import org.springframework.boot.actuate.health.AbstractHealthIndicator;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.HealthIndicator;
+import org.springframework.boot.actuate.health.Status;
+import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
+import org.springframework.util.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@link HealthIndicator} for Sentinel.
+ *
+ * Check the status of Sentinel Dashboard by sending a heartbeat message to it.
+ *
+ * Note: if sentinel isn't enabled or sentinel-dashboard isn't configured,
+ * the health status is up and more infos are provided in detail.
+ *
+ *
+ * @author cdfive
+ */
+public class SentinelHealthIndicator extends AbstractHealthIndicator {
+
+ private SentinelProperties sentinelProperties;
+
+ public SentinelHealthIndicator(SentinelProperties sentinelProperties) {
+ this.sentinelProperties = sentinelProperties;
+ }
+
+ @Override
+ protected void doHealthCheck(Health.Builder builder) throws Exception {
+ Map detailMap = new HashMap<>();
+
+ // If sentinel isn't enabled, set the status up and set the enabled to false in detail
+ if (!sentinelProperties.isEnabled()) {
+ detailMap.put("enabled", false);
+ builder.up().withDetails(detailMap);
+ return;
+ }
+
+ detailMap.put("enabled", true);
+
+ String consoleServer = TransportConfig.getConsoleServer();
+ // If dashboard isn't configured, set the status to UNKNOWN
+ if (StringUtils.isEmpty(consoleServer)) {
+ detailMap.put("dashboard", new Status(Status.UNKNOWN.getCode(), "dashboard isn't configured"));
+ builder.up().withDetails(detailMap);
+ return;
+ }
+
+ // If dashboard is configured, send a heartbeat message to it and check the result
+ HeartbeatSender heartbeatSender = HeartbeatSenderProvider.getHeartbeatSender();
+ boolean result = heartbeatSender.sendHeartbeat();
+ if (result) {
+ detailMap.put("dashboard", Status.UP);
+ builder.up().withDetails(detailMap);
+ } else {
+ detailMap.put("dashboard", new Status(Status.DOWN.getCode(), consoleServer + " can't be connected"));
+ builder.down().withDetails(detailMap);
+ }
+ }
+}
diff --git a/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
new file mode 100644
index 000000000..7baaf2054
--- /dev/null
+++ b/spring-cloud-alibaba-sentinel/src/test/java/org/springframework/cloud/alibaba/sentinel/endpoint/SentinelHealthIndicatorTests.java
@@ -0,0 +1,90 @@
+package org.springframework.cloud.alibaba.sentinel.endpoint;
+
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
+import com.alibaba.csp.sentinel.transport.HeartbeatSender;
+import com.alibaba.csp.sentinel.transport.config.TransportConfig;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.boot.actuate.health.Health;
+import org.springframework.boot.actuate.health.Status;
+import org.springframework.cloud.alibaba.sentinel.SentinelProperties;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.reflect.Field;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test cases for {@link SentinelHealthIndicator}.
+ *
+ * @author cdfive
+ */
+public class SentinelHealthIndicatorTests {
+
+ private SentinelHealthIndicator sentinelHealthIndicator;
+
+ private SentinelProperties sentinelProperties;
+
+ private HeartbeatSender heartbeatSender;
+
+ @Before
+ public void setUp() {
+ sentinelProperties = mock(SentinelProperties.class);
+ sentinelHealthIndicator = new SentinelHealthIndicator(sentinelProperties);
+
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "");
+
+ heartbeatSender = mock(HeartbeatSender.class);
+ Field heartbeatSenderField = ReflectionUtils.findField(HeartbeatSenderProvider.class, "heartbeatSender");
+ heartbeatSenderField.setAccessible(true);
+ ReflectionUtils.setField(heartbeatSenderField, null, heartbeatSender);
+ }
+
+ @Test
+ public void testSentinelNotEnabled() {
+ when(sentinelProperties.isEnabled()).thenReturn(false);
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ assertThat(health.getDetails().get("enabled")).isEqualTo(false);
+ }
+
+ @Test
+ public void testSentinelDashboardNotConfigured() {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ assertThat(health.getDetails().get("dashboard")).isEqualTo(Status.UNKNOWN);
+ }
+
+ @Test
+ public void testSentinelDashboardConfiguredCheckSuccess() throws Exception {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
+ when(heartbeatSender.sendHeartbeat()).thenReturn(true);
+
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.UP);
+ }
+
+ @Test
+ public void testSentinelDashboardConfiguredCheckFailed() throws Exception {
+ when(sentinelProperties.isEnabled()).thenReturn(true);
+ SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, "localhost:8080");
+ when(heartbeatSender.sendHeartbeat()).thenReturn(false);
+
+
+ Health health = sentinelHealthIndicator.health();
+
+ assertThat(health.getStatus()).isEqualTo(Status.DOWN);
+ assertThat(health.getDetails().get("dashboard")).isEqualTo(new Status(Status.DOWN.getCode(), "localhost:8080 can't be connected"));
+ }
+}