diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc
index 401aea7c..a715542f 100644
--- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc
+++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc
@@ -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.
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClient.java
index 9dc081be..0c72d839 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClient.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClient.java
@@ -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
diff --git a/spring-cloud-netflix-turbine/pom.xml b/spring-cloud-netflix-turbine/pom.xml
index e9ff164c..d2d8351b 100644
--- a/spring-cloud-netflix-turbine/pom.xml
+++ b/spring-cloud-netflix-turbine/pom.xml
@@ -38,5 +38,11 @@
com.netflix.turbine
turbine-core
+
+ org.projectlombok
+ lombok
+
+ provided
+
diff --git a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/EurekaInstanceDiscovery.java b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/EurekaInstanceDiscovery.java
index cd610b1d..a8e201e6 100644
--- a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/EurekaInstanceDiscovery.java
+++ b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/EurekaInstanceDiscovery.java
@@ -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;
}
/**
diff --git a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineConfiguration.java b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineConfiguration.java
index 1c535f80..0431ddd8 100644
--- a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineConfiguration.java
+++ b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineConfiguration.java
@@ -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 {
@@ -23,9 +25,14 @@ public class TurbineConfiguration implements SmartLifecycle, Ordered {
return new ServletRegistrationBean(new TurbineStreamServlet(), "/turbine.stream");
}
+ @Bean
+ public TurbineProperties turbineProperties() {
+ return new TurbineProperties();
+ }
+
@Bean
public InstanceDiscovery instanceDiscovery() {
- return new EurekaInstanceDiscovery();
+ return new EurekaInstanceDiscovery(turbineProperties());
}
private boolean running;
diff --git a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineProperties.java b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineProperties.java
new file mode 100644
index 00000000..cb461364
--- /dev/null
+++ b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/TurbineProperties.java
@@ -0,0 +1,13 @@
+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";
+}
diff --git a/spring-cloud-netflix-turbine/src/test/java/org/springframework/cloud/netflix/turbine/EurekaInstanceDiscoveryTest.java b/spring-cloud-netflix-turbine/src/test/java/org/springframework/cloud/netflix/turbine/EurekaInstanceDiscoveryTest.java
new file mode 100644
index 00000000..b2685258
--- /dev/null
+++ b/spring-cloud-netflix-turbine/src/test/java/org/springframework/cloud/netflix/turbine/EurekaInstanceDiscoveryTest.java
@@ -0,0 +1,38 @@
+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);
+ }
+}