diff --git a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc
index 446e24ca1..6f07f6a07 100644
--- a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc
+++ b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc
@@ -305,6 +305,21 @@ By default Sleuth assumes that when you send a span to Zipkin, you want the span
spring.zipkin.service.name: foo
----
+=== Host locator
+
+In order to define the host that is corresponding to a particular span we need to resolve the host name
+and port. The default approach is to take it from server properties. If those for some reason are not set
+then we're trying to retrieve the host name from the network interfaces.
+
+If you have the discovery client enabled and prefer to retrieve the host address from the registered
+instance in a service registry then you have to set the property (it's applicable for both HTTP and
+Stream based span reporting).
+
+[source,yaml]
+----
+spring.zipkin.locator.discovery.enabled: true
+----
+
== Span Data as Messages
You can accumulate and send span data over
diff --git a/spring-cloud-sleuth-stream/pom.xml b/spring-cloud-sleuth-stream/pom.xml
index 48aa8ed39..1082b1a7a 100644
--- a/spring-cloud-sleuth-stream/pom.xml
+++ b/spring-cloud-sleuth-stream/pom.xml
@@ -27,7 +27,6 @@
org.springframework.cloud
spring-cloud-commons
- true
org.springframework.boot
diff --git a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocator.java b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocator.java
index 86b618f6e..172c80eb0 100644
--- a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocator.java
+++ b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocator.java
@@ -52,8 +52,8 @@ public class DiscoveryClientHostLocator implements HostLocator {
@Override
public Host locate(Span span) {
ServiceInstance instance = this.client.getLocalServiceInstance();
- String serviceId = StringUtils.hasText(this.zipkinProperties.getName()) ?
- this.zipkinProperties.getName() : instance.getServiceId();
+ String serviceId = StringUtils.hasText(this.zipkinProperties.getService().getName()) ?
+ this.zipkinProperties.getService().getName() : instance.getServiceId();
return new Host(serviceId, getIpAddress(instance),
instance.getPort());
}
diff --git a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocator.java b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocator.java
index 37e33a582..1a9c90f4d 100644
--- a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocator.java
+++ b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocator.java
@@ -16,8 +16,14 @@
package org.springframework.cloud.sleuth.stream;
+import java.lang.invoke.MethodHandles;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
+import org.springframework.cloud.commons.util.InetUtils;
+import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.cloud.sleuth.Span;
import org.springframework.context.event.EventListener;
import org.springframework.util.Assert;
@@ -32,30 +38,37 @@ import org.springframework.util.StringUtils;
* port - from lazily assigned port or {@link ServerProperties}
*
*
- * You can override the value of service id by {@link ZipkinProperties#setName(String)}
+ * You can override the value of service id by {@link ZipkinProperties#getService()}
*
* @author Dave Syer
* @since 1.0.0
*/
public class ServerPropertiesHostLocator implements HostLocator {
+ private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass());
+
private final ServerProperties serverProperties; // Nullable
private final String appName;
+ private final InetUtils inetUtils;
private final ZipkinProperties zipkinProperties;
private Integer port; // Lazy assigned
@Deprecated
- public ServerPropertiesHostLocator(ServerProperties serverProperties,
- String appName) {
- this(serverProperties, appName, new ZipkinProperties());
+ public ServerPropertiesHostLocator(ServerProperties serverProperties, String appName) {
+ this(serverProperties, appName, new ZipkinProperties(),null);
}
- public ServerPropertiesHostLocator(ServerProperties serverProperties,
- String appName, ZipkinProperties zipkinProperties) {
+ public ServerPropertiesHostLocator(ServerProperties serverProperties, String appName,
+ ZipkinProperties zipkinProperties, InetUtils inetUtils) {
this.serverProperties = serverProperties;
this.appName = appName;
Assert.notNull(this.appName, "appName");
this.zipkinProperties = zipkinProperties;
+ if (inetUtils == null) {
+ this.inetUtils = new InetUtils(new InetUtilsProperties());
+ } else {
+ this.inetUtils = inetUtils;
+ }
}
@Override
@@ -91,21 +104,24 @@ public class ServerPropertiesHostLocator implements HostLocator {
address = this.serverProperties.getAddress().getHostAddress();
}
else {
- address = "127.0.0.1";
+ address = this.inetUtils.findFirstNonLoopbackAddress().getHostAddress();
}
return address;
}
private String getServiceName(Span span) {
String serviceName;
- if (StringUtils.hasText(this.zipkinProperties.getName())) {
- serviceName = this.zipkinProperties.getName();
+ if (StringUtils.hasText(this.zipkinProperties.getService().getName())) {
+ serviceName = this.zipkinProperties.getService().getName();
} else if (span.getProcessId() != null) {
serviceName = span.getProcessId();
}
else {
serviceName = this.appName;
}
+ if (log.isDebugEnabled()) {
+ log.debug("Span will contain serviceName [" + serviceName + "]");
+ }
return serviceName;
}
diff --git a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java
index cd71a167a..eb027ff00 100644
--- a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java
+++ b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java
@@ -22,11 +22,11 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.metric.SpanMetricReporter;
import org.springframework.cloud.sleuth.metric.TraceMetricsAutoConfiguration;
@@ -91,7 +91,8 @@ public class SleuthStreamAutoConfiguration {
}
@Configuration
- @ConditionalOnMissingClass("org.springframework.cloud.client.discovery.DiscoveryClient")
+ @ConditionalOnMissingBean(HostLocator.class)
+ @ConditionalOnProperty(value = "spring.zipkin.locator.discovery.enabled", havingValue = "false", matchIfMissing = true)
protected static class DefaultEndpointLocatorConfiguration {
@Autowired(required = false)
@@ -100,18 +101,24 @@ public class SleuthStreamAutoConfiguration {
@Autowired
private ZipkinProperties zipkinProperties;
+ @Autowired
+ private InetUtils inetUtils;
+
@Value("${spring.application.name:unknown}")
private String appName;
@Bean
public HostLocator zipkinEndpointLocator() {
- return new ServerPropertiesHostLocator(this.serverProperties, this.appName, this.zipkinProperties);
+ return new ServerPropertiesHostLocator(this.serverProperties, this.appName, this.zipkinProperties,
+ this.inetUtils);
}
}
@Configuration
@ConditionalOnClass(DiscoveryClient.class)
+ @ConditionalOnMissingBean(HostLocator.class)
+ @ConditionalOnProperty(value = "spring.zipkin.locator.discovery.enabled", havingValue = "true")
protected static class DiscoveryClientEndpointLocatorConfiguration {
@Autowired(required = false)
@@ -120,6 +127,9 @@ public class SleuthStreamAutoConfiguration {
@Autowired
private ZipkinProperties zipkinProperties;
+ @Autowired(required = false)
+ private InetUtils inetUtils;
+
@Value("${spring.application.name:unknown}")
private String appName;
@@ -131,7 +141,8 @@ public class SleuthStreamAutoConfiguration {
if (this.client != null) {
return new DiscoveryClientHostLocator(this.client, this.zipkinProperties);
}
- return new ServerPropertiesHostLocator(this.serverProperties, this.appName, this.zipkinProperties);
+ return new ServerPropertiesHostLocator(this.serverProperties, this.appName, this.zipkinProperties,
+ this.inetUtils);
}
}
diff --git a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ZipkinProperties.java b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ZipkinProperties.java
index 700ee1023..908de229c 100644
--- a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ZipkinProperties.java
+++ b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/ZipkinProperties.java
@@ -24,17 +24,66 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
* @author Marcin Grzejszczak
* @since 1.0.12
*/
-@ConfigurationProperties("spring.zipkin.service")
+@ConfigurationProperties("spring.zipkin")
public class ZipkinProperties {
- /** The name of the service, from which the Span was sent via Stream, that should appear in Zipkin */
- private String name;
+ private Service service = new Service();
- public String getName() {
- return this.name;
+ private Locator locator = new Locator();
+
+ public Service getService() {
+ return this.service;
}
- public void setName(String name) {
- this.name = name;
+ public void setService(Service service) {
+ this.service = service;
+ }
+
+ public Locator getLocator() {
+ return this.locator;
+ }
+
+ public void setLocator(Locator locator) {
+ this.locator = locator;
+ }
+
+ public static class Service {
+ /** The name of the service, from which the Span was sent via Stream, that should appear in Zipkin */
+ private String name;
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+ }
+
+ public static class Locator {
+
+ private Discovery discovery;
+
+ public Discovery getDiscovery() {
+ return this.discovery;
+ }
+
+ public void setDiscovery(Discovery discovery) {
+ this.discovery = discovery;
+ }
+
+ public static class Discovery {
+
+ /** Enabling of locating the host name via service discovery */
+ private boolean enabled;
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+ }
}
}
diff --git a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/DiscoveryClientEndpointLocatorConfigurationTest.java b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/DiscoveryClientEndpointLocatorConfigurationTest.java
new file mode 100644
index 000000000..c01dd1e16
--- /dev/null
+++ b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/DiscoveryClientEndpointLocatorConfigurationTest.java
@@ -0,0 +1,94 @@
+package org.springframework.cloud.sleuth.stream;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Matcin Wielgus
+ */
+public class DiscoveryClientEndpointLocatorConfigurationTest {
+ @Test
+ public void endpointLocatorShouldDefaultToServerPropertiesEndpointLocator() {
+ try (ConfigurableApplicationContext ctxt = new SpringApplication(
+ EmptyConfiguration.class).run("--spring.main.web_environment=false")) {
+ assertThat(ctxt.getBean(HostLocator.class))
+ .isInstanceOf(ServerPropertiesHostLocator.class);
+ }
+ }
+
+ @Test
+ public void endpointLocatorShouldDefaultToServerPropertiesEndpointLocatorEvenWhenDiscoveryClientPresent() {
+ try (ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithDiscoveryClient.class)
+ .run("--spring.main.web_environment=false")) {
+ assertThat(ctxt.getBean(HostLocator.class))
+ .isInstanceOf(ServerPropertiesHostLocator.class);
+ }
+ }
+
+ @Test
+ public void endpointLocatorShouldRespectExistingEndpointLocator() {
+ try (ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithCustomLocator.class)
+ .run("--spring.main.web_environment=false")) {
+ assertThat(ctxt.getBean(HostLocator.class))
+ .isSameAs(ConfigurationWithCustomLocator.locator);
+ }
+ }
+
+ @Test
+ public void endpointLocatorShouldBeFallbackHavingEndpointLocatorWhenAskedTo() {
+ try (ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithDiscoveryClient.class).run(
+ "--spring.zipkin.locator.discovery.enabled=true",
+ "--spring.main.web_environment=false")) {
+ assertThat(ctxt.getBean(HostLocator.class))
+ .isInstanceOf(DiscoveryClientHostLocator.class);
+ }
+ }
+
+ @Test
+ public void endpointLocatorShouldRespectExistingEndpointLocatorEvenWhenAskedToBeDiscovery() {
+ try (ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithDiscoveryClient.class,
+ ConfigurationWithCustomLocator.class).run(
+ "--spring.zipkin.locator.discovery.enabled=true",
+ "--spring.main.web_environment=false")) {
+ assertThat(ctxt.getBean(HostLocator.class))
+ .isSameAs(ConfigurationWithCustomLocator.locator);
+ }
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class EmptyConfiguration {
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class ConfigurationWithDiscoveryClient {
+ @Bean
+ public DiscoveryClient getDiscoveryClient() {
+ return Mockito.mock(DiscoveryClient.class);
+ }
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class ConfigurationWithCustomLocator {
+ static HostLocator locator = Mockito.mock(HostLocator.class);
+
+ @Bean
+ public HostLocator getEndpointLocator() {
+ return locator;
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocatorTest.java b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocatorTest.java
index 46f4bf72d..b596eed16 100644
--- a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocatorTest.java
+++ b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/DiscoveryClientHostLocatorTest.java
@@ -67,7 +67,7 @@ public class DiscoveryClientHostLocatorTest {
public void should_override_the_service_name_from_properties() throws Exception {
given(this.discoveryClient.getLocalServiceInstance()).willReturn(serviceInstanceWithValidHost());
ZipkinProperties zipkinProperties = new ZipkinProperties();
- zipkinProperties.setName("foo");
+ zipkinProperties.getService().setName("foo");
this.discoveryClientHostLocator = new DiscoveryClientHostLocator(this.discoveryClient, zipkinProperties);
Host host = this.discoveryClientHostLocator.locate(null);
diff --git a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocatorTests.java b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocatorTests.java
index a63c02268..22ca4ea5c 100644
--- a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocatorTests.java
+++ b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/ServerPropertiesHostLocatorTests.java
@@ -21,49 +21,57 @@ import java.net.UnknownHostException;
import java.util.Collections;
import org.junit.Test;
+import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.cloud.commons.util.InetUtils;
+import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.cloud.sleuth.Span;
import static org.assertj.core.api.Assertions.assertThat;
public class ServerPropertiesHostLocatorTests {
+
+ public static final byte[] ADR1234 = { 1, 2, 3, 4 };
+
Span span = new Span(1, 3, "http:name", 1L, Collections.emptyList(), 2L, true, true,
"process");
@Test
- public void portDefaultsTo8080() {
+ public void portDefaultsTo8080() throws UnknownHostException {
ServerPropertiesHostLocator locator = new ServerPropertiesHostLocator(
- new ServerProperties(), "unknown", new ZipkinProperties());
+ new ServerProperties(), "unknown", new ZipkinProperties(),
+ localAddress(ADR1234));
assertThat(locator.locate(this.span).getPort()).isEqualTo((short) 8080);
}
@Test
- public void portFromServerProperties() {
+ public void portFromServerProperties() throws UnknownHostException {
ServerProperties properties = new ServerProperties();
properties.setPort(1234);
ServerPropertiesHostLocator locator = new ServerPropertiesHostLocator(properties,
- "unknown", new ZipkinProperties());
+ "unknown", new ZipkinProperties(),localAddress(ADR1234));
assertThat(locator.locate(this.span).getPort()).isEqualTo((short) 1234);
}
@Test
- public void portDefaultsToLocalhost() {
+ public void portDefaultsToLocalhost() throws UnknownHostException {
ServerPropertiesHostLocator locator = new ServerPropertiesHostLocator(
- new ServerProperties(), "unknown", new ZipkinProperties());
+ new ServerProperties(), "unknown", new ZipkinProperties(),
+ localAddress(ADR1234));
- assertThat(locator.locate(this.span).getAddress()).isEqualTo("127.0.0.1");
+ assertThat(locator.locate(this.span).getAddress()).isEqualTo("1.2.3.4");
}
@Test
public void hostFromServerPropertiesIp() throws UnknownHostException {
ServerProperties properties = new ServerProperties();
- properties.setAddress(InetAddress.getByAddress(new byte[] { 1, 2, 3, 4 }));
+ properties.setAddress(InetAddress.getByAddress(ADR1234));
ServerPropertiesHostLocator locator = new ServerPropertiesHostLocator(properties,
- "unknown", new ZipkinProperties());
+ "unknown", new ZipkinProperties(),localAddress(new byte[] { 1, 1, 1, 1 }));
assertThat(locator.locate(this.span).getAddress()).isEqualTo("1.2.3.4");
}
@@ -73,11 +81,18 @@ public class ServerPropertiesHostLocatorTests {
ServerProperties properties = new ServerProperties();
properties.setAddress(InetAddress.getByAddress(new byte[] { 1, 2, 3, 4 }));
ZipkinProperties zipkinProperties = new ZipkinProperties();
- zipkinProperties.setName("foo");
+ zipkinProperties.getService().setName("foo");
ServerPropertiesHostLocator locator = new ServerPropertiesHostLocator(properties,
- "unknown", zipkinProperties);
+ "unknown", zipkinProperties,localAddress(ADR1234));
assertThat(locator.locate(this.span).getServiceName()).isEqualTo("foo");
}
+
+ private InetUtils localAddress(byte[] address) throws UnknownHostException {
+ InetUtils mocked = Mockito.spy(new InetUtils(new InetUtilsProperties()));
+ Mockito.when(mocked.findFirstNonLoopbackAddress())
+ .thenReturn(InetAddress.getByAddress(address));
+ return mocked;
+ }
}
diff --git a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfigurationTest.java b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfigurationTest.java
index 3e0d02bf1..51cfab3bf 100644
--- a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfigurationTest.java
+++ b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfigurationTest.java
@@ -10,6 +10,7 @@ import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils;
+import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
import org.springframework.cloud.sleuth.log.NoOpSpanLogger;
import org.springframework.cloud.sleuth.log.SpanLogger;
@@ -120,7 +121,7 @@ public class SleuthStreamAutoConfigurationTest {
@Import({ SleuthStreamAutoConfiguration.class, TraceMetricsAutoConfiguration.class,
TestSupportBinderAutoConfiguration.class,
ChannelBindingAutoConfiguration.class, TraceAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class })
+ PropertyPlaceholderAutoConfiguration.class, UtilAutoConfiguration.class })
public static class BaseConfiguration {
@Bean
SpanLogger spanLogger() {
diff --git a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java
index c99df54f0..f26bb6399 100644
--- a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java
+++ b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanListenerTests.java
@@ -33,6 +33,7 @@ import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.metrics.CounterService;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
+import org.springframework.cloud.commons.util.UtilAutoConfiguration;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanReporter;
@@ -158,7 +159,7 @@ public class StreamSpanListenerTests {
@Import({ ZipkinTestConfiguration.class, SleuthStreamAutoConfiguration.class,
TraceMetricsAutoConfiguration.class, TestSupportBinderAutoConfiguration.class,
ChannelBindingAutoConfiguration.class, TraceAutoConfiguration.class,
- PropertyPlaceholderAutoConfiguration.class })
+ PropertyPlaceholderAutoConfiguration.class, UtilAutoConfiguration.class })
protected static class TestConfiguration {
}
diff --git a/spring-cloud-sleuth-zipkin/pom.xml b/spring-cloud-sleuth-zipkin/pom.xml
index 6750fef8c..9e6ebd7c5 100644
--- a/spring-cloud-sleuth-zipkin/pom.xml
+++ b/spring-cloud-sleuth-zipkin/pom.xml
@@ -40,7 +40,6 @@
org.springframework.cloud
spring-cloud-commons
- true
org.springframework.boot
diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/FallbackHavingEndpointLocator.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/FallbackHavingEndpointLocator.java
index 5ac4ca5d2..e9c58805d 100644
--- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/FallbackHavingEndpointLocator.java
+++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/FallbackHavingEndpointLocator.java
@@ -1,7 +1,5 @@
package org.springframework.cloud.sleuth.zipkin;
-import java.util.concurrent.atomic.AtomicReference;
-
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import zipkin.Endpoint;
@@ -14,8 +12,6 @@ import zipkin.Endpoint;
*/
public class FallbackHavingEndpointLocator implements EndpointLocator {
- private final AtomicReference cachedEndpoint = new AtomicReference<>();
-
private static final Log log = LogFactory.getLog(FallbackHavingEndpointLocator.class);
private final DiscoveryClientEndpointLocator discoveryClientEndpointLocator;
@@ -29,8 +25,7 @@ public class FallbackHavingEndpointLocator implements EndpointLocator {
@Override
public Endpoint local() {
- this.cachedEndpoint.compareAndSet(null, endpoint());
- return this.cachedEndpoint.get();
+ return endpoint();
}
private Endpoint endpoint() {
diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocator.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocator.java
index b148b5ff9..8749914a9 100644
--- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocator.java
+++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocator.java
@@ -17,12 +17,14 @@
package org.springframework.cloud.sleuth.zipkin;
import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent;
import org.springframework.cloud.commons.util.InetUtils;
+import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;
@@ -47,20 +49,25 @@ public class ServerPropertiesEndpointLocator implements EndpointLocator {
private final ServerProperties serverProperties;
private final String appName;
+ private final InetUtils inetUtils;
private final ZipkinProperties zipkinProperties;
private Integer port;
@Deprecated
- public ServerPropertiesEndpointLocator(ServerProperties serverProperties,
- String appName) {
- this(serverProperties, appName, new ZipkinProperties());
+ public ServerPropertiesEndpointLocator(ServerProperties serverProperties,String appName) {
+ this(serverProperties,appName,new ZipkinProperties(), null);
}
public ServerPropertiesEndpointLocator(ServerProperties serverProperties,
- String appName, ZipkinProperties zipkinProperties) {
+ String appName, ZipkinProperties zipkinProperties, InetUtils inetUtils) {
this.serverProperties = serverProperties;
this.appName = appName;
this.zipkinProperties = zipkinProperties;
+ if (inetUtils == null) {
+ this.inetUtils = new InetUtils(new InetUtilsProperties());
+ } else {
+ this.inetUtils = inetUtils;
+ }
}
@Override
@@ -97,11 +104,12 @@ public class ServerPropertiesEndpointLocator implements EndpointLocator {
}
private int getAddress() {
- if (this.serverProperties!=null && this.serverProperties.getAddress() != null) {
- return InetUtils.getIpAddressAsInt(this.serverProperties.getAddress().getHostAddress());
+ if (this.serverProperties != null && this.serverProperties.getAddress() != null) {
+ return ByteBuffer.wrap(this.serverProperties.getAddress().getAddress())
+ .getInt();
}
else {
- return 127 << 24 | 1;
+ return ByteBuffer.wrap(this.inetUtils.findFirstNonLoopbackAddress().getAddress()).getInt();
}
}
}
diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java
index 829f7aa33..01082bdb1 100644
--- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java
+++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java
@@ -21,11 +21,11 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.sleuth.Sampler;
import org.springframework.cloud.sleuth.SpanReporter;
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
@@ -70,7 +70,8 @@ public class ZipkinAutoConfiguration {
}
@Configuration
- @ConditionalOnMissingClass("org.springframework.cloud.client.discovery.DiscoveryClient")
+ @ConditionalOnMissingBean(EndpointLocator.class)
+ @ConditionalOnProperty(value = "spring.zipkin.locator.discovery.enabled", havingValue = "false", matchIfMissing = true)
protected static class DefaultEndpointLocatorConfiguration {
@Autowired(required=false)
@@ -79,19 +80,24 @@ public class ZipkinAutoConfiguration {
@Autowired
private ZipkinProperties zipkinProperties;
+ @Autowired(required=false)
+ private InetUtils inetUtils;
+
@Value("${spring.application.name:unknown}")
private String appName;
@Bean
public EndpointLocator zipkinEndpointLocator() {
return new ServerPropertiesEndpointLocator(this.serverProperties, this.appName,
- this.zipkinProperties);
+ this.zipkinProperties, this.inetUtils);
}
}
@Configuration
@ConditionalOnClass(DiscoveryClient.class)
+ @ConditionalOnMissingBean(EndpointLocator.class)
+ @ConditionalOnProperty(value = "spring.zipkin.locator.discovery.enabled", havingValue = "true")
protected static class DiscoveryClientEndpointLocatorConfiguration {
@Autowired(required=false)
@@ -100,6 +106,9 @@ public class ZipkinAutoConfiguration {
@Autowired
private ZipkinProperties zipkinProperties;
+ @Autowired(required=false)
+ private InetUtils inetUtils;
+
@Value("${spring.application.name:unknown}")
private String appName;
@@ -110,7 +119,7 @@ public class ZipkinAutoConfiguration {
public EndpointLocator zipkinEndpointLocator() {
return new FallbackHavingEndpointLocator(discoveryClientEndpointLocator(),
new ServerPropertiesEndpointLocator(this.serverProperties, this.appName,
- this.zipkinProperties));
+ this.zipkinProperties, this.inetUtils));
}
private DiscoveryClientEndpointLocator discoveryClientEndpointLocator() {
diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java
index 1a27fd047..1144d0d0c 100644
--- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java
+++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinProperties.java
@@ -34,6 +34,12 @@ public class ZipkinProperties {
private Service service = new Service();
+ private Locator locator = new Locator();
+
+ public Locator getLocator() {
+ return this.locator;
+ }
+
public String getBaseUrl() {
return this.baseUrl;
}
@@ -74,6 +80,10 @@ public class ZipkinProperties {
this.service = service;
}
+ public void setLocator(Locator locator) {
+ this.locator = locator;
+ }
+
/** When enabled, spans are gzipped before sent to the zipkin server */
public static class Compression {
@@ -102,4 +112,31 @@ public class ZipkinProperties {
this.name = name;
}
}
+
+ public static class Locator {
+
+ private Discovery discovery;
+
+ public Discovery getDiscovery() {
+ return this.discovery;
+ }
+
+ public void setDiscovery(Discovery discovery) {
+ this.discovery = discovery;
+ }
+
+ public static class Discovery {
+
+ /** Enabling of locating the host name via service discovery */
+ private boolean enabled;
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+ }
+ }
}
diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java
index f00aa22d3..4b33fdf91 100644
--- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java
+++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java
@@ -119,7 +119,7 @@ public class ZipkinSpanListener implements SpanReporter {
return zipkinSpan.build();
}
- private void ensureLocalComponent(Span span, zipkin.Span.Builder zipkinSpan) {
+ private void ensureLocalComponent(Span span, zipkin.Span.Builder zipkinSpan, Endpoint localEndpoint) {
if (span.tags().containsKey(Constants.LOCAL_COMPONENT)) {
return;
}
@@ -130,14 +130,14 @@ public class ZipkinSpanListener implements SpanReporter {
.type(BinaryAnnotation.Type.STRING)
.key("lc") // LOCAL_COMPONENT
.value(processId)
- .endpoint(this.endpointLocator.local()).build();
+ .endpoint(localEndpoint).build();
zipkinSpan.addBinaryAnnotation(component);
}
- private void ensureServerAddr(Span span, zipkin.Span.Builder zipkinSpan) {
+ private void ensureServerAddr(Span span, zipkin.Span.Builder zipkinSpan, Endpoint localEndpoint) {
if (span.tags().containsKey(Span.SPAN_PEER_SERVICE_TAG_NAME)) {
zipkinSpan.addBinaryAnnotation(BinaryAnnotation.address(Constants.SERVER_ADDR,
- this.endpointLocator.local().toBuilder().serviceName(
+ localEndpoint.toBuilder().serviceName(
span.tags().get(Span.SPAN_PEER_SERVICE_TAG_NAME)).build()));
}
}
@@ -160,10 +160,10 @@ public class ZipkinSpanListener implements SpanReporter {
}
if (notClientOrServer) {
// A zipkin span without any annotations cannot be queried, add special "lc" to avoid that.
- ensureLocalComponent(span, zipkinSpan);
+ ensureLocalComponent(span, zipkinSpan, endpoint);
}
if (hasClientSend) {
- ensureServerAddr(span, zipkinSpan);
+ ensureServerAddr(span, zipkinSpan, endpoint);
}
if (instanceIdToTag && this.environment != null) {
setInstanceIdIfPresent(zipkinSpan, endpoint, Span.INSTANCEID);
diff --git a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/DiscoveryClientEndpointLocatorConfigurationTest.java b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/DiscoveryClientEndpointLocatorConfigurationTest.java
new file mode 100644
index 000000000..510d18899
--- /dev/null
+++ b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/DiscoveryClientEndpointLocatorConfigurationTest.java
@@ -0,0 +1,89 @@
+package org.springframework.cloud.sleuth.zipkin;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Matcin Wielgus
+ */
+public class DiscoveryClientEndpointLocatorConfigurationTest {
+
+ @Test
+ public void endpointLocatorShouldDefaultToServerPropertiesEndpointLocator() {
+ ConfigurableApplicationContext ctxt = new SpringApplication(
+ EmptyConfiguration.class).run();
+ assertThat(ctxt.getBean(EndpointLocator.class))
+ .isInstanceOf(ServerPropertiesEndpointLocator.class);
+ ctxt.close();
+ }
+
+ @Test
+ public void endpointLocatorShouldDefaultToServerPropertiesEndpointLocatorEvenWhenDiscoveryClientPresent() {
+ ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithDiscoveryClient.class).run();
+ assertThat(ctxt.getBean(EndpointLocator.class))
+ .isInstanceOf(ServerPropertiesEndpointLocator.class);
+ ctxt.close();
+ }
+
+ @Test
+ public void endpointLocatorShouldRespectExistingEndpointLocator() {
+ ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithCustomLocator.class).run();
+ assertThat(ctxt.getBean(EndpointLocator.class))
+ .isSameAs(ConfigurationWithCustomLocator.locator);
+ ctxt.close();
+ }
+
+ @Test
+ public void endpointLocatorShouldBeFallbackHavingEndpointLocatorWhenAskedTo() {
+ ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithDiscoveryClient.class).run("--spring.zipkin.locator.discovery.enabled=true");
+ assertThat(ctxt.getBean(EndpointLocator.class))
+ .isInstanceOf(FallbackHavingEndpointLocator.class);
+ ctxt.close();
+ }
+
+ @Test
+ public void endpointLocatorShouldRespectExistingEndpointLocatorEvenWhenAskedToBeDiscovery() {
+ ConfigurableApplicationContext ctxt = new SpringApplication(
+ ConfigurationWithDiscoveryClient.class,ConfigurationWithCustomLocator.class).run("--spring.zipkin.locator.discovery.enabled=true");
+ assertThat(ctxt.getBean(EndpointLocator.class))
+ .isSameAs(ConfigurationWithCustomLocator.locator);
+ ctxt.close();
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class EmptyConfiguration {
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class ConfigurationWithDiscoveryClient {
+ @Bean
+ public DiscoveryClient getDiscoveryClient() {
+ return Mockito.mock(DiscoveryClient.class);
+ }
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ public static class ConfigurationWithCustomLocator {
+ static EndpointLocator locator = Mockito.mock(EndpointLocator.class);
+
+ @Bean
+ public EndpointLocator getEndpointLocator() {
+ return locator;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/HttpZipkinSpanReporterTest.java b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/HttpZipkinSpanReporterTest.java
index e5b0a9b1e..a7b9ddb82 100644
--- a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/HttpZipkinSpanReporterTest.java
+++ b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/HttpZipkinSpanReporterTest.java
@@ -6,6 +6,8 @@ import java.util.concurrent.atomic.AtomicReference;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.cloud.commons.util.InetUtils;
+import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.cloud.sleuth.DefaultSpanNamer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.log.NoOpSpanLogger;
@@ -130,7 +132,7 @@ public class HttpZipkinSpanReporterTest {
Tracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(), new DefaultSpanNamer(),
new NoOpSpanLogger(), new ZipkinSpanListener(receivedSpan::set,
new ServerPropertiesEndpointLocator(new ServerProperties(), "foo",
- new ZipkinProperties())));
+ new ZipkinProperties(), new InetUtils(new InetUtilsProperties()))));
// tag::service_name[]
org.springframework.cloud.sleuth.Span newSpan = tracer.createSpan("redis");
try {
diff --git a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocatorTests.java b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocatorTests.java
index 2614388f5..92304542c 100644
--- a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocatorTests.java
+++ b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ServerPropertiesEndpointLocatorTests.java
@@ -20,46 +20,53 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import org.junit.Test;
+import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.cloud.commons.util.InetUtils;
+import org.springframework.cloud.commons.util.InetUtilsProperties;
import static org.assertj.core.api.Assertions.assertThat;
public class ServerPropertiesEndpointLocatorTests {
+ public static final byte[] ADDRESS1234 = { 1, 2, 3, 4 };
+
@Test
- public void portDefaultsTo8080() {
+ public void portDefaultsTo8080() throws UnknownHostException {
ServerPropertiesEndpointLocator locator = new ServerPropertiesEndpointLocator(
- new ServerProperties(), "unknown", new ZipkinProperties());
+ new ServerProperties(), "unknown", new ZipkinProperties(),
+ localAddress(ADDRESS1234));
assertThat(locator.local().port).isEqualTo((short) 8080);
}
@Test
- public void portFromServerProperties() {
+ public void portFromServerProperties() throws UnknownHostException {
ServerProperties properties = new ServerProperties();
properties.setPort(1234);
ServerPropertiesEndpointLocator locator = new ServerPropertiesEndpointLocator(
- properties, "unknown", new ZipkinProperties());
+ properties, "unknown", new ZipkinProperties(),localAddress(ADDRESS1234));
assertThat(locator.local().port).isEqualTo((short) 1234);
}
@Test
- public void portDefaultsToLocalhost() {
+ public void portDefaultsToLocalhost() throws UnknownHostException {
ServerPropertiesEndpointLocator locator = new ServerPropertiesEndpointLocator(
- new ServerProperties(), "unknown", new ZipkinProperties());
+ new ServerProperties(), "unknown", new ZipkinProperties(), localAddress(ADDRESS1234));
- assertThat(locator.local().ipv4).isEqualTo(127 << 24 | 1);
+ assertThat(locator.local().ipv4).isEqualTo(1 << 24 | 2 << 16 | 3 << 8 | 4);
}
@Test
public void hostFromServerPropertiesIp() throws UnknownHostException {
ServerProperties properties = new ServerProperties();
- properties.setAddress(InetAddress.getByAddress(new byte[] { 1, 2, 3, 4 }));
+ properties.setAddress(InetAddress.getByAddress(ADDRESS1234));
ServerPropertiesEndpointLocator locator = new ServerPropertiesEndpointLocator(
- properties, "unknown", new ZipkinProperties());
+ properties, "unknown", new ZipkinProperties(),
+ localAddress(new byte[] { 4, 4, 4, 4 }));
assertThat(locator.local().ipv4).isEqualTo(1 << 24 | 2 << 16 | 3 << 8 | 4);
}
@@ -71,8 +78,15 @@ public class ServerPropertiesEndpointLocatorTests {
zipkinProperties.getService().setName("foo");
ServerPropertiesEndpointLocator locator = new ServerPropertiesEndpointLocator(
- properties, "unknown", zipkinProperties);
+ properties, "unknown", zipkinProperties,localAddress(ADDRESS1234));
assertThat(locator.local().serviceName).isEqualTo("foo");
}
+
+ private InetUtils localAddress(byte[] address) throws UnknownHostException {
+ InetUtils mocked = Mockito.spy(new InetUtils(new InetUtilsProperties()));
+ Mockito.when(mocked.findFirstNonLoopbackAddress())
+ .thenReturn(InetAddress.getByAddress(address));
+ return mocked;
+ }
}