Commit ce5b1bbb by Spencer Gibb

allow customization of turbine clusterName via SPEL expression in applcation.properties.

Fixes gh-49
parent 766ac6b8
......@@ -306,7 +306,7 @@ To run the Hystrix Dashboard annotate your Spring Boot main class with `@EnableH
Looking at an individual instances Hystrix data is not very useful in terms of the overall health of the system. https://github.com/Netflix/Turbine[Turbine] is an application that aggregates all of the relevant `/hystrix.stream` endpoints into a combined `/turbine.stream` for use in the Hystrix Dashboard. Individual instances are located via Eureka. Running Turbine is as simple as annotating your main class with the `@EnableTurbine` annotation.
`turbine.appConfig` is a list of eureka serviceId's that turbine will use to lookup instances. `turbine.aggregator.clusterConfig` is used to group instances together. This comes from the eureka `InstanceInfo`. It is currently hard coded to `InstanceInfo.getAppName()`. The turbine stream is then used in the Hystrix dashboard using a url that looks like: http://my.turbine.sever:8080/turbine.stream?cluster=CUSTOMERS
`turbine.appConfig` is a list of eureka serviceId's that turbine will use to lookup instances. `turbine.aggregator.clusterConfig` is used to group instances together. This comes from the eureka `InstanceInfo`. The clusterName is a SPEL expression evaluated against the InstanceInfo. The default clusterNameExpression is `appName`. The turbine stream is then used in the Hystrix dashboard using a url that looks like: http://my.turbine.sever:8080/turbine.stream?cluster=CUSTOMERS
The `cluster` parameter must match an entry in `turbine.aggregator.clusterConfig`.
......@@ -317,6 +317,8 @@ turbine:
appConfig: customers
----
The clusterName can be customized by a SPEL expression in `turbine.clusterNameExpression`. For example, `turbine.clusterNameExpression=aSGName` would get the clustername from the AWS ASG name.
== Declarative REST Client: Feign
https://github.com/Netflix/feign[Feign] is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same `HttpMessageConverters` used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.
......
......@@ -3,7 +3,6 @@ package org.springframework.cloud.netflix.eureka;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
/**
* @author Spencer Gibb
......
......@@ -38,5 +38,11 @@
<groupId>com.netflix.turbine</groupId>
<artifactId>turbine-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- Only needed at compile time -->
<scope>provided</scope>
</dependency>
</dependencies>
</project>
......@@ -12,6 +12,9 @@ import com.netflix.turbine.discovery.Instance;
import com.netflix.turbine.discovery.InstanceDiscovery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import java.util.*;
......@@ -29,10 +32,15 @@ public class EurekaInstanceDiscovery implements InstanceDiscovery {
// Property the controls the list of applications that are enabled in Eureka
private static final DynamicStringProperty ApplicationList = DynamicPropertyFactory.getInstance().getStringProperty("turbine.appConfig", "");
public EurekaInstanceDiscovery() {
private final Expression clusterNameExpression;
public EurekaInstanceDiscovery(TurbineProperties turbineProperties) {
// Eureka client should already be configured by spring-platform-netflix-core
// initialize eureka client.
//DiscoveryManager.getInstance().initComponent(new MyDataCenterInstanceConfig(), new DefaultEurekaClientConfig());
SpelExpressionParser parser = new SpelExpressionParser();
clusterNameExpression = parser.parseExpression(turbineProperties.getClusterNameExpression());
}
/**
......@@ -162,10 +170,12 @@ public class EurekaInstanceDiscovery implements InstanceDiscovery {
* @return
*/
protected String getClusterName(InstanceInfo iInfo) {
//TODO: make ASG configurable using app name for demo. //return iInfo.getASGName();
//AppGroupName is UPPERCASE from eureka
//return iInfo.getAppGroupName();
return iInfo.getAppName();
StandardEvaluationContext context = new StandardEvaluationContext(iInfo);
Object value = clusterNameExpression.getValue(context);
if (value != null) {
return value.toString();
}
return null;
}
/**
......
......@@ -5,6 +5,7 @@ import com.netflix.turbine.init.TurbineInit;
import com.netflix.turbine.plugins.PluginsFactory;
import com.netflix.turbine.streaming.servlet.TurbineStreamServlet;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
......@@ -15,6 +16,7 @@ import org.springframework.core.Ordered;
* @author Spencer Gibb
*/
@Configuration
@EnableConfigurationProperties
@EnableEurekaClient
public class TurbineConfiguration implements SmartLifecycle, Ordered {
......@@ -24,8 +26,13 @@ public class TurbineConfiguration implements SmartLifecycle, Ordered {
}
@Bean
public TurbineProperties turbineProperties() {
return new TurbineProperties();
}
@Bean
public InstanceDiscovery instanceDiscovery() {
return new EurekaInstanceDiscovery();
return new EurekaInstanceDiscovery(turbineProperties());
}
private boolean running;
......
package org.springframework.cloud.netflix.turbine;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Spencer Gibb
*/
@Data
@ConfigurationProperties("turbine")
public class TurbineProperties {
private String clusterNameExpression = "appName";
}
package org.springframework.cloud.netflix.turbine;
import static org.junit.Assert.*;
import com.netflix.appinfo.InstanceInfo;
import org.junit.Test;
/**
* @author Spencer Gibb
*/
public class EurekaInstanceDiscoveryTest {
@Test
public void testGetClusterName() {
String appName = "testAppName";
EurekaInstanceDiscovery discovery = new EurekaInstanceDiscovery(new TurbineProperties());
InstanceInfo instanceInfo = InstanceInfo.Builder.newBuilder()
.setAppName(appName)
.build();
String clusterName = discovery.getClusterName(instanceInfo);
assertEquals("clusterName is wrong", appName.toUpperCase(), clusterName);
}
@Test
public void testGetClusterNameCustomExpression() {
TurbineProperties turbineProperties = new TurbineProperties();
turbineProperties.setClusterNameExpression("aSGName");
EurekaInstanceDiscovery discovery = new EurekaInstanceDiscovery(turbineProperties);
String asgName = "myAsgName";
InstanceInfo instanceInfo = InstanceInfo.Builder.newBuilder()
.setAppName("testApp")
.setASGName(asgName)
.build();
String clusterName = discovery.getClusterName(instanceInfo);
assertEquals("clusterName is wrong", asgName, clusterName);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment