Moved zipkin load balancing to runtime

without this change we resolved the Zipkin URL only at startup
with this change whenever we are to send a span to Zipkin we will try to resolve the URL via Discovery Client (if applicable)

fixes #642
This commit is contained in:
Marcin Grzejszczak
2017-07-15 22:02:57 +02:00
parent a626632b40
commit 64a9577e4c

View File

@@ -17,9 +17,12 @@
package org.springframework.cloud.sleuth.zipkin;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
@@ -42,6 +45,10 @@ import org.springframework.cloud.sleuth.sampler.SamplerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
/**
@@ -73,13 +80,16 @@ public class ZipkinAutoConfiguration {
@ConditionalOnMissingBean
public ZipkinSpanReporter reporter(SpanMetricReporter spanMetricReporter, ZipkinProperties zipkin,
ZipkinRestTemplateCustomizer zipkinRestTemplateCustomizer) {
RestTemplate restTemplate = new RestTemplate();
RestTemplate restTemplate = zipkinRestTemplate(zipkin);
zipkinRestTemplateCustomizer.customize(restTemplate);
String zipkinUrl = this.extractor.zipkinUrl(zipkin);
return new HttpZipkinSpanReporter(restTemplate, zipkinUrl, zipkin.getFlushInterval(),
return new HttpZipkinSpanReporter(restTemplate, zipkin.getBaseUrl(), zipkin.getFlushInterval(),
spanMetricReporter);
}
private RestTemplate zipkinRestTemplate(ZipkinProperties zipkinProperties) {
return new ZipkinRestTemplateWrapper(zipkinProperties, this.extractor);
}
@Configuration
@ConditionalOnClass(DiscoveryClient.class)
static class DiscoveryClientZipkinUrlExtractorConfiguration {
@@ -91,16 +101,16 @@ public class ZipkinAutoConfiguration {
final DiscoveryClient discoveryClient = this.discoveryClient;
return new ZipkinUrlExtractor() {
@Override
public String zipkinUrl(ZipkinProperties zipkinProperties) {
public URI zipkinUrl(ZipkinProperties zipkinProperties) {
if (discoveryClient != null) {
URI uri = URI.create(zipkinProperties.getBaseUrl());
String host = uri.getHost();
List<ServiceInstance> instances = discoveryClient.getInstances(host);
if (!instances.isEmpty()) {
return instances.get(0).getUri().toString();
return instances.get(0).getUri();
}
}
return zipkinProperties.getBaseUrl();
return URI.create(zipkinProperties.getBaseUrl());
}
};
}
@@ -113,8 +123,8 @@ public class ZipkinAutoConfiguration {
ZipkinUrlExtractor zipkinUrlExtractor() {
return new ZipkinUrlExtractor() {
@Override
public String zipkinUrl(ZipkinProperties zipkinProperties) {
return zipkinProperties.getBaseUrl();
public URI zipkinUrl(ZipkinProperties zipkinProperties) {
return URI.create(zipkinProperties.getBaseUrl());
}
};
}
@@ -202,6 +212,51 @@ public class ZipkinAutoConfiguration {
}
/**
* Internal interface to provide a way to retrieve Zipkin URI. If there's no discovery client
* then this value will be taken from the properties. Otherwise host will be assumed to
* be a service id.
*/
interface ZipkinUrlExtractor {
String zipkinUrl(ZipkinProperties zipkinProperties);
URI zipkinUrl(ZipkinProperties zipkinProperties);
}
/**
* Resolves at runtime where the Zipkin server is. If there's no discovery client then
* {@link URI} from the properties is taken. Otherwise service discovery is pinged
* for current Zipkin address.
*/
class ZipkinRestTemplateWrapper extends RestTemplate {
private static final Log log = LogFactory.getLog(ZipkinRestTemplateWrapper.class);
private final ZipkinProperties zipkinProperties;
private final ZipkinUrlExtractor extractor;
ZipkinRestTemplateWrapper(ZipkinProperties zipkinProperties,
ZipkinUrlExtractor extractor) {
this.zipkinProperties = zipkinProperties;
this.extractor = extractor;
}
@Override protected <T> T doExecute(URI originalUrl, HttpMethod method,
RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor) throws RestClientException {
URI uri = this.extractor.zipkinUrl(this.zipkinProperties);
URI newUri = resolvedZipkinUri(originalUrl, uri);
return super.doExecute(newUri, method, requestCallback, responseExtractor);
}
private URI resolvedZipkinUri(URI originalUrl, URI resolvedZipkinUri) {
try {
return new URI(resolvedZipkinUri.getScheme(), resolvedZipkinUri.getUserInfo(),
resolvedZipkinUri.getHost(), resolvedZipkinUri.getPort(), originalUrl.getPath(),
originalUrl.getQuery(), originalUrl.getFragment());
} catch (URISyntaxException e) {
if (log.isDebugEnabled()) {
log.debug("Failed to create the new URI from original [" + originalUrl + "] and new one [" + resolvedZipkinUri + "]");
}
return originalUrl;
}
}
}