diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index 91f3e284..cc0e1aba 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -393,7 +393,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`. 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 +Configuration key `turbine.appConfig` is a list of eureka serviceId's that turbine will use to lookup instances. And `turbine.aggregator.clusterConfig` is used to group instances together (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`. @@ -406,7 +406,17 @@ 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. +The `clusterName` can be customized by a SPEL expression in `turbine.clusterNameExpression`. For example, `turbine.clusterNameExpression=aSGName` would get the cluster name from the AWS ASG name. + +Spring Cloud provides a `spring-cloud-starter-turbine` that has all the dependencies you need to get a Turbine server running. Just create a Spring Boot application and annotate it with `@EnableTurbine`. + +=== Turbine AMQP + +In some environments (e.g. in a PaaS setting), the classic Turbine model of pulling metrics from all the distributed Hystrix commands doesn't work. In that case you might want to have your Hystrix commands push metrics to Turbine, and Spring Cloud enables that with AMQP messaging. All you need to do on the client is add a dependency to `spring-cloud-netflix-hystrix-amqp` and make sure there is a Rabbit brooker available (see Spring Boot documentation for details on how to configure the client credentials, but it should work out of the box for a local broker or in Cloud Foundry). + +On the server side Just create a Spring Boot application and annotate it with `@EnableTurbineAmqp` and by default it will come up on port 8989 (point your Hystrix dashboard to that port, any path). You can customize the port using either `server.port` or `turbine.amqp.port`. If you have `spring-boot-starter-web` and `spring-boot-starter-actuator` on the classpath as well, then you can open up the Actuator endpoints on a separate port (with Tomcat by default) by providing a `management.port` which is different. + +Spring Cloud provides a `spring-cloud-starter-turbine-amqp` that has all the dependencies you need to get a Turbine AMQP server running. You need Java 8 to run the app because it is Netty-based. [[spring-cloud-feign]] == Declarative REST Client: Feign diff --git a/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpConfiguration.java b/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpConfiguration.java index 8d9f42da..a6367dfe 100644 --- a/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpConfiguration.java +++ b/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpConfiguration.java @@ -15,8 +15,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.context.SmartLifecycle; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - import org.springframework.util.SocketUtils; + import rx.Observable; import rx.subjects.PublishSubject; @@ -36,6 +36,7 @@ public class TurbineAmqpConfiguration implements SmartLifecycle { @Autowired private TurbineAmqpProperties turbine; + private int turbinePort; @Bean diff --git a/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpProperties.java b/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpProperties.java index caa0ba78..b866ab77 100644 --- a/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpProperties.java +++ b/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpProperties.java @@ -2,6 +2,7 @@ package org.springframework.cloud.netflix.turbine.amqp; import lombok.Data; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; /** @@ -11,6 +12,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties; @Data public class TurbineAmqpProperties { + @Value("${server.port:8989}") private int port = 8989; } diff --git a/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbinePortSpringApplicationRunListener.java b/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbinePortSpringApplicationRunListener.java new file mode 100644 index 00000000..a046ae59 --- /dev/null +++ b/spring-cloud-netflix-turbine-amqp/src/main/java/org/springframework/cloud/netflix/turbine/amqp/TurbinePortSpringApplicationRunListener.java @@ -0,0 +1,35 @@ +package org.springframework.cloud.netflix.turbine.amqp; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.core.env.MapPropertySource; + +public class TurbinePortSpringApplicationRunListener implements + ApplicationListener { + + @Override + public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { + Integer serverPort = event.getEnvironment().getProperty("server.port", + Integer.class); + Integer managementPort = event.getEnvironment().getProperty("management.port", + Integer.class); + Integer turbinePort = event.getEnvironment().getProperty("turbine.amqp.port", + Integer.class); + if (serverPort == null && managementPort == null) { + return; + } + if (serverPort != -1) { + Map ports = new HashMap(); + ports.put("server.port", -1); + if (serverPort != null && turbinePort==null) { + ports.put("turbine.amqp.port", serverPort); + } + event.getEnvironment().getPropertySources() + .addFirst(new MapPropertySource("ports", ports)); + } + } + +} diff --git a/spring-cloud-netflix-turbine-amqp/src/main/resources/META-INF/spring.factories b/spring-cloud-netflix-turbine-amqp/src/main/resources/META-INF/spring.factories index ee13e692..7bd15928 100644 --- a/spring-cloud-netflix-turbine-amqp/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-netflix-turbine-amqp/src/main/resources/META-INF/spring.factories @@ -1,2 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.netflix.turbine.amqp.TurbineAmqpAutoConfiguration + +org.springframework.context.ApplicationListener=\ +org.springframework.cloud.netflix.turbine.amqp.TurbinePortSpringApplicationRunListener \ No newline at end of file diff --git a/spring-cloud-netflix-turbine-amqp/src/test/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpTests.java b/spring-cloud-netflix-turbine-amqp/src/test/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpTests.java index 1c5508f0..78fc142d 100644 --- a/spring-cloud-netflix-turbine-amqp/src/test/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpTests.java +++ b/spring-cloud-netflix-turbine-amqp/src/test/java/org/springframework/cloud/netflix/turbine/amqp/TurbineAmqpTests.java @@ -17,6 +17,7 @@ import org.springframework.test.context.web.WebAppConfiguration; @WebAppConfiguration @IntegrationTest({ "server.port=0", "turbine.amqp.port=0", "spring.jmx.enabled=true" }) public class TurbineAmqpTests { + @EnableAutoConfiguration @EnableTurbineAmqp public static class Application {