diff --git a/README.adoc b/README.adoc
index 4b30082a6..ab8207b34 100644
--- a/README.adoc
+++ b/README.adoc
@@ -322,6 +322,7 @@ Example of setting baggage on a span:
----
Span initialSpan = this.tracer.createSpan("span");
initialSpan.setBaggageItem("foo", "bar");
+initialSpan.setBaggageItem("UPPER_CASE", "someValue");
----
===== Baggage vs. Span Tags
diff --git a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc
index f1175c263..bbf232e53 100644
--- a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc
+++ b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc
@@ -484,6 +484,26 @@ Stream based span reporting).
spring.zipkin.locator.discovery.enabled: true
----
+== Sending spans to Zipkin
+
+By default if you add `spring-cloud-starter-zipkin` as a dependency to your project,
+when the span is closed, it will be sent to Zipkin over HTTP. The communication
+is asynchronous. You can configure the URL by setting the `spring.zipkin.baseUrl`
+property as follows:
+
+[source,yaml]
+----
+spring.zipkin.baseUrl: http://192.168.99.100:9411/
+----
+
+If you want to find Zipkin via service discovery it's enough to pass the
+Zipkin's service id inside the URL (example for `zipkinserver` service id)
+
+[source,yaml]
+----
+spring.zipkin.baseUrl: http://zipkinserver/
+----
+
== Span Data as Messages
You can accumulate and send span data over
diff --git a/pom.xml b/pom.xml
index 1b22ce281..2b03f2271 100644
--- a/pom.xml
+++ b/pom.xml
@@ -226,12 +226,6 @@
3.0.0
test
-
- com.github.tomakehurst
- wiremock
- 2.6.0
- test
-
pl.pragmatists
JUnitParams
diff --git a/spring-cloud-sleuth-zipkin/pom.xml b/spring-cloud-sleuth-zipkin/pom.xml
index 8b6883210..5e0b36e69 100644
--- a/spring-cloud-sleuth-zipkin/pom.xml
+++ b/spring-cloud-sleuth-zipkin/pom.xml
@@ -88,6 +88,11 @@
zipkin-junit
test
+
+ org.awaitility
+ awaitility
+ test
+
com.squareup.okhttp3
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 da83b58e6..ce8f33d2f 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
@@ -16,6 +16,7 @@
package org.springframework.cloud.sleuth.zipkin;
+import java.net.URI;
import java.util.ArrayList;
import java.util.List;
@@ -24,9 +25,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.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.sleuth.Sampler;
@@ -64,6 +67,7 @@ import org.springframework.web.client.RestTemplate;
public class ZipkinAutoConfiguration {
@Autowired(required = false) List spanAdjusters = new ArrayList<>();
+ @Autowired ZipkinUrlExtractor extractor;
@Bean
@ConditionalOnMissingBean
@@ -71,10 +75,51 @@ public class ZipkinAutoConfiguration {
ZipkinRestTemplateCustomizer zipkinRestTemplateCustomizer) {
RestTemplate restTemplate = new RestTemplate();
zipkinRestTemplateCustomizer.customize(restTemplate);
- return new HttpZipkinSpanReporter(restTemplate, zipkin.getBaseUrl(), zipkin.getFlushInterval(),
+ String zipkinUrl = this.extractor.zipkinUrl(zipkin);
+ return new HttpZipkinSpanReporter(restTemplate, zipkinUrl, zipkin.getFlushInterval(),
spanMetricReporter);
}
+ @Configuration
+ @ConditionalOnClass(DiscoveryClient.class)
+ static class DiscoveryClientZipkinUrlExtractorConfiguration {
+
+ @Autowired(required = false) DiscoveryClient discoveryClient;
+
+ @Bean
+ ZipkinUrlExtractor zipkinUrlExtractor() {
+ final DiscoveryClient discoveryClient = this.discoveryClient;
+ return new ZipkinUrlExtractor() {
+ @Override
+ public String zipkinUrl(ZipkinProperties zipkinProperties) {
+ if (discoveryClient != null) {
+ URI uri = URI.create(zipkinProperties.getBaseUrl());
+ String host = uri.getHost();
+ List instances = discoveryClient.getInstances(host);
+ if (!instances.isEmpty()) {
+ return instances.get(0).getUri().toString();
+ }
+ }
+ return zipkinProperties.getBaseUrl();
+ }
+ };
+ }
+ }
+
+ @Configuration
+ @ConditionalOnMissingClass("org.springframework.cloud.client.discovery.DiscoveryClient")
+ static class DefaultZipkinUrlExtractorConfiguration {
+ @Bean
+ ZipkinUrlExtractor zipkinUrlExtractor() {
+ return new ZipkinUrlExtractor() {
+ @Override
+ public String zipkinUrl(ZipkinProperties zipkinProperties) {
+ return zipkinProperties.getBaseUrl();
+ }
+ };
+ }
+ }
+
@Bean
@ConditionalOnMissingBean
public ZipkinRestTemplateCustomizer zipkinRestTemplateCustomizer(ZipkinProperties zipkinProperties) {
@@ -156,3 +201,7 @@ public class ZipkinAutoConfiguration {
}
}
+
+interface ZipkinUrlExtractor {
+ String zipkinUrl(ZipkinProperties zipkinProperties);
+}
\ No newline at end of file
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 1144d0d0c..037a9dc2f 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
@@ -26,7 +26,10 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
*/
@ConfigurationProperties("spring.zipkin")
public class ZipkinProperties {
- /** URL of the zipkin query server instance. */
+ /** URL of the zipkin query server instance. You can also provide
+ * the service id of the Zipkin server if Zipkin's registered in
+ * service discovery (e.g. http://zipkinserver/)
+ */
private String baseUrl = "http://localhost:9411/";
private boolean enabled = true;
private int flushInterval = 1;
diff --git a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinDiscoveryClientTests.java b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinDiscoveryClientTests.java
new file mode 100644
index 000000000..80027526c
--- /dev/null
+++ b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinDiscoveryClientTests.java
@@ -0,0 +1,118 @@
+package org.springframework.cloud.sleuth.zipkin;
+
+import static org.assertj.core.api.BDDAssertions.then;
+import static org.springframework.cloud.sleuth.zipkin.ZipkinDiscoveryClientTests.ZIPKIN_RULE;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.assertj.core.api.BDDAssertions;
+import org.awaitility.Awaitility;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.sleuth.Span;
+import org.springframework.cloud.sleuth.SpanReporter;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.util.SocketUtils;
+
+import zipkin.junit.ZipkinRule;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = ZipkinDiscoveryClientTests.Config.class,
+ properties = "spring.zipkin.baseUrl=http://zipkin/")
+public class ZipkinDiscoveryClientTests {
+
+ @ClassRule public static ZipkinRule ZIPKIN_RULE = new ZipkinRule();
+
+ @Autowired SpanReporter spanReporter;
+
+ @Test
+ public void shouldUseDiscoveryClientToFindZipkinUrlIfPresent() throws Exception {
+ Span span = Span.builder().traceIdHigh(1L).traceId(2L).spanId(3L).name("foo")
+ .build();
+
+ this.spanReporter.report(span);
+
+ Awaitility.await().untilAsserted(() -> then(ZIPKIN_RULE.httpRequestCount()).isGreaterThan(0));
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ static class Config {
+ @Bean
+ DiscoveryClient client() {
+ return new ZipkinDiscoveryClient();
+ }
+ }
+}
+
+
+class ZipkinDiscoveryClient implements DiscoveryClient {
+
+ @Override
+ public String description() {
+ return "";
+ }
+
+ @Override
+ public ServiceInstance getLocalServiceInstance() {
+ return null;
+ }
+
+ @Override
+ public List getInstances(String s) {
+ if ("zipkin".equals(s)) {
+ return Collections.singletonList(new ServiceInstance() {
+ @Override
+ public String getServiceId() {
+ return "zipkin";
+ }
+
+ @Override
+ public String getHost() {
+ return "localhost";
+ }
+
+ @Override
+ public int getPort() {
+ return URI.create(ZIPKIN_RULE.httpUrl()).getPort();
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public URI getUri() {
+ return URI.create(ZIPKIN_RULE.httpUrl());
+ }
+
+ @Override
+ public Map getMetadata() {
+ return null;
+ }
+ });
+ }
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List getServices() {
+ return Collections.singletonList("zipkin");
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java
index b5aecddaa..878cd5c8b 100644
--- a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java
+++ b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java
@@ -17,11 +17,16 @@
package org.springframework.cloud.sleuth.zipkin;
import org.assertj.core.api.Condition;
+import org.junit.Ignore;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
import zipkin.Constants;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import javax.annotation.PostConstruct;
import org.junit.Test;
@@ -56,7 +61,6 @@ import static org.junit.Assert.assertEquals;
public class ZipkinSpanListenerTests {
@Autowired Tracer tracer;
- @Autowired ApplicationContext application;
@Autowired TestConfiguration test;
@Autowired ZipkinSpanListener spanListener;
@Autowired ZipkinSpanReporter spanReporter;
@@ -337,4 +341,4 @@ public class ZipkinSpanListenerTests {
}
-}
+}
\ No newline at end of file