1
0
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:
fangjian0423 2019-06-17 11:05:59 +08:00
parent 7229bc8615
commit 9ccb1d5de4
4 changed files with 171 additions and 57 deletions

View File

@ -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());
}
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}
}

View File

@ -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
}
]
}