diff --git a/docs/src/main/asciidoc/spring-cloud-netflix.adoc b/docs/src/main/asciidoc/spring-cloud-netflix.adoc index 044a3404..3a3dc484 100644 --- a/docs/src/main/asciidoc/spring-cloud-netflix.adoc +++ b/docs/src/main/asciidoc/spring-cloud-netflix.adoc @@ -590,6 +590,16 @@ 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 (e.g. using spring-cloud-starter-turbine to set up the classpath). All of the documented configuration properties from https://github.com/Netflix/Turbine/wiki/Configuration-(1.x)[the Turbine 1 wiki] apply. The only difference is that the `turbine.instanceUrlSuffix` does not need the port prepended as this is handled automatically unless `turbine.instanceInsertPort=false`. +NOTE: By default, Turbine looks for the `/hystrix.stream` endpoint on a registered instance by looking up its `homePageUrl` entry in Eureka, then appending `/hystrix.stream` to it. This means that if `spring-boot-actuator` is running on its own port (which is the default), the call to `/hystrix.stream` will fail. +To make turbine find the Hystrix stream at the correct port, you need to add `management.port` to the instances' metadata: +---- +eureka: + instance: + metadata-map: + management.port: ${management.port:8081} +---- + + The configuration key `turbine.appConfig` is a list of eureka serviceIds that turbine will use to lookup instances. The turbine stream is then used in the Hystrix dashboard using a url that looks like: `http://my.turbine.sever:8080/turbine.stream?cluster=` (the cluster parameter can be omitted if the name is "default"). The `cluster` parameter must match an entry in `turbine.aggregator.clusterConfig`. Values returned from eureka are uppercase, thus we expect this example to work if there is an app registered with Eureka called "customers": ---- diff --git a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscovery.java b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscovery.java index 6f4e0dd1..c83a7f5d 100644 --- a/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscovery.java +++ b/spring-cloud-netflix-turbine/src/main/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscovery.java @@ -157,7 +157,8 @@ public class CommonsInstanceDiscovery implements InstanceDiscovery { */ Instance marshall(ServiceInstance serviceInstance) { String hostname = serviceInstance.getHost(); - String port = String.valueOf(serviceInstance.getPort()); + String managementPort = serviceInstance.getMetadata().get("management.port"); + String port = managementPort == null ? String.valueOf(serviceInstance.getPort()) : managementPort; String cluster = getClusterName(serviceInstance); Boolean status = Boolean.TRUE; //TODO: where to get? if (hostname != null && cluster != null && status != null) { 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 1f2ff8ae..9bf33e00 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 @@ -100,7 +100,8 @@ public class EurekaInstanceDiscovery extends CommonsInstanceDiscovery { */ Instance marshall(InstanceInfo instanceInfo) { String hostname = instanceInfo.getHostName(); - String port = String.valueOf(instanceInfo.getPort()); + final String managementPort = instanceInfo.getMetadata().get("management.port"); + String port = managementPort == null ? String.valueOf(instanceInfo.getPort()) : managementPort; String cluster = getClusterName(instanceInfo); Boolean status = parseInstanceStatus(instanceInfo.getStatus()); if (hostname != null && cluster != null && status != null) { diff --git a/spring-cloud-netflix-turbine/src/test/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscoveryTest.java b/spring-cloud-netflix-turbine/src/test/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscoveryTest.java index be44dd30..cd586cf0 100644 --- a/spring-cloud-netflix-turbine/src/test/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscoveryTest.java +++ b/spring-cloud-netflix-turbine/src/test/java/org/springframework/cloud/netflix/turbine/CommonsInstanceDiscoveryTest.java @@ -100,7 +100,23 @@ public class CommonsInstanceDiscoveryTest { assertEquals("url is wrong", "http://"+hostName+":"+port+"/hystrix.stream", urlPath); } - @Test + @Test + public void testUseManagementPortFromMetadata() { + CommonsInstanceDiscovery discovery = createDiscovery(); + String appName = "testAppName"; + int port = 8080; + int managementPort = 8081; + String hostName = "myhost"; + DefaultServiceInstance serviceInstance = new DefaultServiceInstance(appName, hostName, port, false); + serviceInstance.getMetadata().put("management.port", String.valueOf(managementPort)); + Instance instance = discovery.marshall(serviceInstance); + assertEquals("port is wrong", String.valueOf(managementPort), instance.getAttributes().get("port")); + + String urlPath = SpringClusterMonitor.ClusterConfigBasedUrlClosure.getUrlPath(instance); + assertEquals("url is wrong", "http://"+hostName+":"+managementPort+"/hystrix.stream", urlPath); + } + + @Test public void testGetSecurePort() { CommonsInstanceDiscovery discovery = createDiscovery(); String appName = "testAppName"; 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 index 5c677295..c7807c69 100644 --- 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 @@ -89,12 +89,35 @@ public class EurekaInstanceDiscoveryTest { } @Test - public void testGetClusterName() { - EurekaInstanceDiscovery discovery = new EurekaInstanceDiscovery( - turbineProperties, eurekaClient); + public void testUseManagementPortFromMetadata() { + EurekaInstanceDiscovery discovery = new EurekaInstanceDiscovery(turbineProperties, + eurekaClient); String appName = "testAppName"; - InstanceInfo instanceInfo = builder.setAppName(appName) + int port = 8080; + int managementPort = 8081; + String hostName = "myhost"; + InstanceInfo instanceInfo = builder.setAppName(appName).setHostName(hostName).setPort(port) .build(); + instanceInfo.getMetadata().put("management.port", "8081"); + Instance instance = discovery.marshall(instanceInfo); + assertEquals("hostname is wrong", hostName + ":" + managementPort, instance.getHostname()); + assertEquals("port is wrong", String.valueOf(managementPort), + instance.getAttributes().get("port")); + + String urlPath = SpringClusterMonitor.ClusterConfigBasedUrlClosure.getUrlPath(instance); + assertEquals("url is wrong", + "http://" + hostName + ":" + managementPort + "/hystrix.stream", urlPath); + + String clusterName = discovery.getClusterName(instanceInfo); + assertEquals("clusterName is wrong", appName.toUpperCase(), clusterName); + } + + @Test + public void testGetClusterName() { + EurekaInstanceDiscovery discovery = new EurekaInstanceDiscovery(turbineProperties, + eurekaClient); + String appName = "testAppName"; + InstanceInfo instanceInfo = builder.setAppName(appName).build(); String clusterName = discovery.getClusterName(instanceInfo); assertEquals("clusterName is wrong", appName.toUpperCase(), clusterName); }