Due to possible performance problems when DiscoveryClient gives nonexistent DNS name as local address Local endpoint is created from server properties by default.
Local Ip determined from spring.commons InetUtils.
To enable local endpoint resolution via service discovery, DiscoveryClient must be present and 'spring.zipkin.service.locator.discovery' should be set to true.
FallbackHavingEndpointLocator was caching and recreating EndpointLocator in the same time - removed the caching part.
Fixes gh-403
This commit is contained in:
@@ -298,6 +298,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
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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,24 +38,37 @@ import org.springframework.util.StringUtils;
|
||||
* <li><b>port</b> - from lazily assigned port or {@link ServerProperties}</li>
|
||||
* </ul>
|
||||
*
|
||||
* 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
|
||||
|
||||
public ServerPropertiesHostLocator(ServerProperties serverProperties,
|
||||
String appName, ZipkinProperties zipkinProperties) {
|
||||
@Deprecated
|
||||
public ServerPropertiesHostLocator(ServerProperties serverProperties, String appName) {
|
||||
this(serverProperties, appName, new ZipkinProperties(),null);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -85,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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.<Long>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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.junit.After;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.cloud.commons.util.UtilAutoConfiguration;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.log.NoOpSpanLogger;
|
||||
@@ -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() {
|
||||
|
||||
@@ -35,6 +35,7 @@ import org.springframework.boot.actuate.metrics.CounterService;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
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;
|
||||
@@ -159,7 +160,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 {
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -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<Endpoint> 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() {
|
||||
|
||||
@@ -19,12 +19,14 @@ package org.springframework.cloud.sleuth.zipkin;
|
||||
import zipkin.Endpoint;
|
||||
|
||||
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,14 +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(), 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
|
||||
@@ -91,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -88,7 +88,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)
|
||||
@@ -97,19 +98,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)
|
||||
@@ -118,6 +124,9 @@ public class ZipkinAutoConfiguration {
|
||||
@Autowired
|
||||
private ZipkinProperties zipkinProperties;
|
||||
|
||||
@Autowired(required=false)
|
||||
private InetUtils inetUtils;
|
||||
|
||||
@Value("${spring.application.name:unknown}")
|
||||
private String appName;
|
||||
|
||||
@@ -128,7 +137,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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
package org.springframework.cloud.sleuth.zipkin;
|
||||
|
||||
import zipkin.Span;
|
||||
import zipkin.junit.HttpFailure;
|
||||
import zipkin.junit.ZipkinRule;
|
||||
|
||||
import java.util.Random;
|
||||
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.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
@@ -21,6 +19,10 @@ import org.springframework.cloud.sleuth.trace.DefaultTracer;
|
||||
import org.springframework.cloud.sleuth.util.ExceptionUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import zipkin.Span;
|
||||
import zipkin.junit.HttpFailure;
|
||||
import zipkin.junit.ZipkinRule;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
@@ -128,7 +130,8 @@ public class HttpZipkinSpanReporterTest {
|
||||
AtomicReference<Span> receivedSpan = new AtomicReference<>();
|
||||
Tracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(), new DefaultSpanNamer(),
|
||||
new NoOpSpanLogger(), new ZipkinSpanListener(receivedSpan::set,
|
||||
new ServerPropertiesEndpointLocator(new ServerProperties(), "foo", new ZipkinProperties())), new TraceKeys());
|
||||
new ServerPropertiesEndpointLocator(new ServerProperties(), "foo",
|
||||
new ZipkinProperties(), new InetUtils(new InetUtilsProperties()))), new TraceKeys());
|
||||
// tag::service_name[]
|
||||
org.springframework.cloud.sleuth.Span newSpan = tracer.createSpan("redis");
|
||||
try {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user