mirror of
https://gitee.com/mirrors/Spring-Cloud-Alibaba.git
synced 2021-06-26 13:25:11 +08:00
sync sentinel healthindicator and log check in finchley
This commit is contained in:
parent
7229bc8615
commit
9ccb1d5de4
@ -18,11 +18,9 @@ package org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -35,13 +33,11 @@ import org.springframework.cloud.alibaba.sentinel.datasource.config.DataSourcePr
|
||||
import org.springframework.cloud.alibaba.sentinel.datasource.converter.JsonConverter;
|
||||
import org.springframework.cloud.alibaba.sentinel.datasource.converter.XmlConverter;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.alibaba.csp.sentinel.datasource.AbstractDataSource;
|
||||
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
|
||||
import com.alibaba.csp.sentinel.slots.block.AbstractRule;
|
||||
|
||||
/**
|
||||
* Sentinel {@link ReadableDataSource} Handler Handle the configurations of
|
||||
@ -210,61 +206,8 @@ public class SentinelDataSourceHandler implements SmartInitializingSingleton {
|
||||
AbstractDataSource newDataSource = (AbstractDataSource) this.beanFactory
|
||||
.getBean(dataSourceName);
|
||||
|
||||
logAndCheckRuleType(newDataSource, dataSourceName,
|
||||
dataSourceProperties.getRuleType().getClazz());
|
||||
|
||||
// register property in RuleManager
|
||||
dataSourceProperties.postRegister(newDataSource);
|
||||
}
|
||||
|
||||
private void logAndCheckRuleType(AbstractDataSource dataSource, String dataSourceName,
|
||||
Class<? extends AbstractRule> ruleClass) {
|
||||
Object ruleConfig;
|
||||
try {
|
||||
ruleConfig = dataSource.loadConfig();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("[Sentinel Starter] DataSource " + dataSourceName
|
||||
+ " loadConfig error: " + e.getMessage(), e);
|
||||
return;
|
||||
}
|
||||
if (ruleConfig instanceof List || ruleConfig instanceof Set) {
|
||||
Collection convertedRuleList = (Collection) ruleConfig;
|
||||
if (CollectionUtils.isEmpty(convertedRuleList)) {
|
||||
log.warn("[Sentinel Starter] DataSource {} rule list is empty.",
|
||||
dataSourceName);
|
||||
return;
|
||||
}
|
||||
int matchCount = 0;
|
||||
for (Object rule : convertedRuleList) {
|
||||
if (rule.getClass() == ruleClass) {
|
||||
matchCount++;
|
||||
}
|
||||
}
|
||||
if (matchCount == 0) {
|
||||
log.error("[Sentinel Starter] DataSource {} none rules are {} type.",
|
||||
dataSourceName, ruleClass.getSimpleName());
|
||||
throw new IllegalArgumentException("[Sentinel Starter] DataSource "
|
||||
+ dataSourceName + " none rules are " + ruleClass.getSimpleName()
|
||||
+ " type.");
|
||||
}
|
||||
else if (matchCount != convertedRuleList.size()) {
|
||||
log.warn("[Sentinel Starter] DataSource {} all rules are not {} type.",
|
||||
dataSourceName, ruleClass.getSimpleName());
|
||||
}
|
||||
else {
|
||||
log.info("[Sentinel Starter] DataSource {} load {} {}", dataSourceName,
|
||||
convertedRuleList.size(), ruleClass.getSimpleName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.error("[Sentinel Starter] DataSource " + dataSourceName
|
||||
+ " rule class is not List<" + ruleClass.getSimpleName()
|
||||
+ ">. Class: " + ruleConfig.getClass());
|
||||
throw new IllegalArgumentException("[Sentinel Starter] DataSource "
|
||||
+ dataSourceName + " rule class is not List<"
|
||||
+ ruleClass.getSimpleName() + ">. Class: " + ruleConfig.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.alibaba.sentinel.endpoint;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator;
|
||||
import org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
@ -38,4 +40,13 @@ public class SentinelEndpointAutoConfiguration {
|
||||
return new SentinelEndpoint(sentinelProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnEnabledHealthIndicator("sentinel")
|
||||
public SentinelHealthIndicator sentinelHealthIndicator(
|
||||
DefaultListableBeanFactory beanFactory,
|
||||
SentinelProperties sentinelProperties) {
|
||||
return new SentinelHealthIndicator(beanFactory, sentinelProperties);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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
|
||||
*
|
||||
* http://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.cloud.alibaba.sentinel.endpoint;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
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 com.alibaba.csp.sentinel.datasource.AbstractDataSource;
|
||||
import com.alibaba.csp.sentinel.heartbeat.HeartbeatSenderProvider;
|
||||
import com.alibaba.csp.sentinel.transport.HeartbeatSender;
|
||||
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
|
||||
|
||||
/**
|
||||
* A {@link HealthIndicator} for Sentinel, which checks the status of Sentinel Dashboard
|
||||
* and DataSource.
|
||||
*
|
||||
* <p>
|
||||
* Check the status of Sentinel Dashboard by sending a heartbeat message to it. If return
|
||||
* true, it's OK.
|
||||
*
|
||||
* Check the status of Sentinel DataSource by calling loadConfig method of
|
||||
* {@link AbstractDataSource}. If no Exception thrown, it's OK.
|
||||
*
|
||||
* If Dashboard and DataSource are both OK, the health status is UP.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Note: If Sentinel isn't enabled, the health status is up. If Sentinel Dashboard isn't
|
||||
* configured, it's OK and mark the status of Dashboard with UNKNOWN. More informations
|
||||
* are provided in details.
|
||||
* </p>
|
||||
*
|
||||
* @author cdfive
|
||||
*/
|
||||
public class SentinelHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
private SentinelProperties sentinelProperties;
|
||||
|
||||
public SentinelHealthIndicator(DefaultListableBeanFactory beanFactory,
|
||||
SentinelProperties sentinelProperties) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.sentinelProperties = sentinelProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
Map<String, Object> 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);
|
||||
withDetails(builder.up(), detailMap);
|
||||
return;
|
||||
}
|
||||
|
||||
detailMap.put("enabled", true);
|
||||
|
||||
// Check health of Dashboard
|
||||
boolean dashboardUp = true;
|
||||
String consoleServer = TransportConfig.getConsoleServer();
|
||||
if (StringUtils.isEmpty(consoleServer)) {
|
||||
// If Dashboard isn't configured, it's OK and mark the status of Dashboard
|
||||
// with UNKNOWN.
|
||||
detailMap.put("dashboard",
|
||||
new Status(Status.UNKNOWN.getCode(), "dashboard isn't configured"));
|
||||
}
|
||||
else {
|
||||
// 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);
|
||||
}
|
||||
else {
|
||||
// If failed to send heartbeat message, means that the Dashboard is DOWN
|
||||
dashboardUp = false;
|
||||
detailMap.put("dashboard", new Status(Status.DOWN.getCode(),
|
||||
consoleServer + " can't be connected"));
|
||||
}
|
||||
}
|
||||
|
||||
// Check health of DataSource
|
||||
boolean dataSourceUp = true;
|
||||
Map<String, Object> dataSourceDetailMap = new HashMap<>();
|
||||
detailMap.put("dataSource", dataSourceDetailMap);
|
||||
|
||||
// Get all DataSources and each call loadConfig to check if it's OK
|
||||
// If no Exception thrown, it's OK
|
||||
// Note:
|
||||
// Even if the dynamic config center is down, the loadConfig() might return
|
||||
// successfully
|
||||
// e.g. for Nacos client, it might retrieve from the local cache)
|
||||
// But in most circumstances it's okay
|
||||
Map<String, AbstractDataSource> dataSourceMap = beanFactory
|
||||
.getBeansOfType(AbstractDataSource.class);
|
||||
for (Map.Entry<String, AbstractDataSource> dataSourceMapEntry : dataSourceMap
|
||||
.entrySet()) {
|
||||
String dataSourceBeanName = dataSourceMapEntry.getKey();
|
||||
AbstractDataSource dataSource = dataSourceMapEntry.getValue();
|
||||
try {
|
||||
dataSource.loadConfig();
|
||||
dataSourceDetailMap.put(dataSourceBeanName, Status.UP);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// If one DataSource failed to loadConfig, means that the DataSource is
|
||||
// DOWN
|
||||
dataSourceUp = false;
|
||||
dataSourceDetailMap.put(dataSourceBeanName,
|
||||
new Status(Status.DOWN.getCode(), e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// If Dashboard and DataSource are both OK, the health status is UP
|
||||
if (dashboardUp && dataSourceUp) {
|
||||
withDetails(builder.up(), detailMap);
|
||||
}
|
||||
else {
|
||||
withDetails(builder.down(), detailMap);
|
||||
}
|
||||
}
|
||||
|
||||
private void withDetails(Health.Builder builder, Map<String, Object> detailMap) {
|
||||
for (String key : detailMap.keySet()) {
|
||||
builder.withDetail(key, detailMap.get(key));
|
||||
}
|
||||
}
|
||||
}
|
@ -94,6 +94,12 @@
|
||||
"name": "feign.sentinel.enabled",
|
||||
"description": "If true, an OpenFeign client will be wrapped with a Sentinel circuit breaker.",
|
||||
"type": "java.lang.Boolean"
|
||||
},
|
||||
{
|
||||
"name": "management.health.sentinel.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Whether to enable sentinel health check.",
|
||||
"defaultValue": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user