diff --git a/spring-cloud-sleuth-dependencies/pom.xml b/spring-cloud-sleuth-dependencies/pom.xml
index dac807076..8805fdcf3 100644
--- a/spring-cloud-sleuth-dependencies/pom.xml
+++ b/spring-cloud-sleuth-dependencies/pom.xml
@@ -63,6 +63,16 @@
brave-core
${brave.version}
+
+ com.github.kristofa
+ brave-http
+ ${brave.version}
+
+
+ com.github.kristofa
+ brave-spring-web-servlet-interceptor
+ ${brave.version}
+
org.aspectj
aspectjrt
diff --git a/spring-cloud-sleuth-samples/pom.xml b/spring-cloud-sleuth-samples/pom.xml
index 62d08837e..02c1d8648 100644
--- a/spring-cloud-sleuth-samples/pom.xml
+++ b/spring-cloud-sleuth-samples/pom.xml
@@ -46,11 +46,48 @@
+
+ org.springframework.cloud
+ spring-cloud-sleuth-dependencies
+ ${project.version}
+ pom
+ import
+
org.springframework.cloud
spring-cloud-sleuth-sample-test-core
${project.version}
+
+ org.testcontainers
+ docker-compose
+ 0.9.8
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ ${testcontainers.jackson.version}
+ compile
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ ${testcontainers.jackson.version}
+ compile
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ ${testcontainers.jackson.version}
+ compile
+
+
+ io.zipkin
+ zipkin-java-core
+ 0.1.2
+ compile
+
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/pom.xml
index 20b9f92a4..aebe8ec36 100644
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/pom.xml
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/pom.xml
@@ -118,6 +118,11 @@
${testcontainers.jackson.version}
compile
+
+ org.testcontainers
+ docker-compose
+ test
+
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationDockerTests.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationDockerTests.java
index 2e571eb9c..996e0e1c2 100644
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationDockerTests.java
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationDockerTests.java
@@ -31,9 +31,8 @@ import org.springframework.util.JdkIdGenerator;
import org.springframework.util.StringUtils;
import org.testcontainers.containers.DockerComposeContainer;
import sample.SampleMessagingApplication;
-import tools.AbstractIntegrationTest;
+import tools.AbstractDockerIntegrationTest;
import tools.IntegrationTestSpanCollector;
-import tools.RequestSendingRunnable;
import java.io.File;
import java.util.Collection;
@@ -41,11 +40,11 @@ import java.util.Collection;
import static org.assertj.core.api.BDDAssertions.then;
@RunWith(SpringJUnit4ClassRunner.class)
-@SpringApplicationConfiguration(classes = { AbstractIntegrationTest.Config.class, SampleMessagingApplication.class })
+@SpringApplicationConfiguration(classes = { AbstractDockerIntegrationTest.Config.class, SampleMessagingApplication.class })
@WebIntegrationTest
@TestPropertySource(properties="sample.zipkin.enabled=true")
@Slf4j
-public class MessagingApplicationDockerTests extends AbstractIntegrationTest {
+public class MessagingApplicationDockerTests extends AbstractDockerIntegrationTest {
private static int port = 3381;
private static String sampleAppUrl = "http://localhost:" + port;
@@ -94,10 +93,6 @@ public class MessagingApplicationDockerTests extends AbstractIntegrationTest {
.anyMatch(binaryAnnotationKey::equals)).isTrue();
}
- private RequestSendingRunnable httpMessageWithTraceIdInHeadersIsSuccessfullySent(String endpoint, String traceId) {
- return new RequestSendingRunnable(restTemplate, endpoint, traceId);
- }
-
private void thenAllSpansHaveTraceIdEqualTo(String traceId) {
then(integrationTestSpanCollector.hashedSpans.stream().allMatch(span -> span.getTrace_id() == zipkinHashedTraceId(traceId))).isTrue();
}
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/pom.xml
index 113b330bc..d8b452d8e 100644
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/pom.xml
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/pom.xml
@@ -16,6 +16,11 @@
..
+
+ 1.8
+ 1.8
+
+
@@ -28,6 +33,21 @@
+
+
+
+ org.codehaus.mojo
+ animal-sniffer-maven-plugin
+
+ true
+
+ org.codehaus.mojo.signature
+ java17
+ 1.0
+
+
+
+
@@ -35,10 +55,6 @@
org.springframework.boot
spring-boot-starter-web
-
- org.springframework.boot
- spring-boot-starter-integration
-
org.springframework.cloud
spring-cloud-sleuth-core
@@ -69,11 +85,6 @@
1.3
compile
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
org.assertj
assertj-core
@@ -84,34 +95,25 @@
awaitility
compile
-
- org.testcontainers
- docker-compose
- 0.9.8
- compile
-
com.fasterxml.jackson.core
jackson-databind
- ${testcontainers.jackson.version}
- compile
com.fasterxml.jackson.core
jackson-core
- ${testcontainers.jackson.version}
- compile
com.fasterxml.jackson.core
jackson-annotations
- ${testcontainers.jackson.version}
- compile
+
+
+ org.testcontainers
+ docker-compose
io.zipkin
zipkin-java-core
- compile
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/AbstractDockerIntegrationTest.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/AbstractDockerIntegrationTest.java
new file mode 100644
index 000000000..156199c99
--- /dev/null
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/AbstractDockerIntegrationTest.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2013-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package tools;
+
+import com.github.kristofa.brave.SpanCollector;
+import com.github.kristofa.brave.scribe.ScribeSpanCollector;
+import com.jayway.awaitility.Awaitility;
+import com.jayway.awaitility.core.ConditionFactory;
+import io.zipkin.Codec;
+import io.zipkin.Span;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.sleuth.zipkin.ZipkinProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.*;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.net.URI;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.assertj.core.api.BDDAssertions.then;
+
+/**
+ * @author Marcin Grzejszczak
+ */
+@Slf4j
+public abstract class AbstractDockerIntegrationTest {
+
+ protected static int pollInterval = 1;
+ protected static int timeout = 120;
+ protected RestTemplate restTemplate = new AssertingRestTemplate();
+
+ public static ConditionFactory await() {
+ return Awaitility.await().pollInterval(pollInterval, SECONDS).atMost(timeout, SECONDS);
+ }
+
+ protected long zipkinHashedTraceId(String string) {
+ long h = 1125899906842597L;
+ if (string == null) {
+ return h;
+ }
+ int len = string.length();
+
+ for (int i = 0; i < len; i++) {
+ h = 31 * h + string.charAt(i);
+ }
+ return h;
+ }
+
+ protected String zipkinHashedHexStringTraceId(String traceId) {
+ long hashedTraceId = zipkinHashedTraceId(traceId);
+ return Long.toHexString(hashedTraceId);
+ }
+
+ public static String getDockerUrl() {
+ URI dockerUri = getDockerURI();
+ if (StringUtils.isEmpty(dockerUri.getScheme())) {
+ return "http://localhost";
+ }
+ return "http://" + dockerUri.getHost();
+ }
+
+ public static URI getDockerURI() {
+ String dockerHost = System.getenv("DOCKER_HOST");
+ if (StringUtils.isEmpty(dockerHost)) {
+ return URI.create("http://localhost");
+ }
+ return URI.create(dockerHost);
+ }
+
+ protected Runnable zipkinQueryServerIsUp() {
+ return checkServerHealth("Zipkin Query Server", this::endpointToCheckZipkinQueryHealth);
+ }
+
+ protected Runnable zipkinServerIsUp() {
+ return checkServerHealth("Zipkin Stream Server", this::endpointToCheckZipkinServerHealth);
+ }
+
+ protected Runnable zipkinCollectorServerIsUp() {
+ return checkServerHealth("Zipkin collector", this::endpointToCheckZipkinCollectorHealth);
+ }
+
+ protected Runnable checkServerHealth(String appName, RequestExchanger requestExchanger) {
+ return () -> {
+ ResponseEntity response = requestExchanger.exchange();
+ log.info("Response from the [{}] health endpoint is [{}]", appName, response);
+ then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ log.info("[{}] is up!", appName);
+ };
+ }
+
+ private interface RequestExchanger {
+ ResponseEntity exchange();
+ }
+
+ protected ResponseEntity endpointToCheckZipkinQueryHealth() {
+ URI uri = URI.create(getZipkinServicesQueryUrl());
+ log.info("Sending request to the Zipkin query service [{}]", uri);
+ return exchangeRequest(uri);
+ }
+
+ protected ResponseEntity endpointToCheckZipkinServerHealth() {
+ URI uri = URI.create("http://localhost:9411/health");
+ log.info("Sending request to the Zipkin Server [{}]", uri);
+ return exchangeRequest(uri);
+ }
+
+ protected ResponseEntity endpointToCheckZipkinCollectorHealth() {
+ URI uri = URI.create(getZipkinCollectorHealthUrl());
+ log.info("Sending request to the Zipkin collector service [{}]", uri);
+ return exchangeRequest(uri);
+ }
+
+ protected ResponseEntity checkStateOfTheTraceId(String traceId) {
+ String hexTraceId = zipkinHashedHexStringTraceId(traceId);
+ URI uri = URI.create(getZipkinTraceQueryUrl() + hexTraceId);
+ log.info("Sending request to the Zipkin query service [{}]. Checking presence of trace id [{}] and its hex version [{}]", uri, traceId, hexTraceId);
+ return exchangeRequest(uri);
+ }
+
+ protected ResponseEntity exchangeRequest(URI uri) {
+ return restTemplate.exchange(
+ new RequestEntity<>(new HttpHeaders(), HttpMethod.GET, uri), String.class
+ );
+ }
+
+ protected String getZipkinTraceQueryUrl() {
+ return getZipkinRootUrl() + ":9411/api/v1/trace/";
+ }
+
+ protected String getZipkinRootUrl() {
+ return getDockerUrl();
+ }
+
+ protected String getZipkinServicesQueryUrl() {
+ return getDockerUrl() + ":9411/api/v1/services";
+ }
+
+ protected String getZipkinServerHealthUrl() {
+ return getDockerUrl() + ":9411/health";
+ }
+
+ protected String getZipkinCollectorHealthUrl() {
+ return getDockerUrl() + ":9900/health";
+ }
+
+ protected Runnable httpMessageWithTraceIdInHeadersIsSuccessfullySent(String endpoint, String traceId) {
+ return new RequestSendingRunnable(restTemplate, endpoint, traceId);
+ }
+
+ protected Runnable allSpansWereRegisteredInZipkinWithTraceIdEqualTo(String traceId) {
+ return () -> {
+ ResponseEntity response = checkStateOfTheTraceId(traceId);
+ log.info("Response from the Zipkin query service about the trace id [{}] for trace with id [{}]", response, traceId);
+ then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ then(response.hasBody()).isTrue();
+ List spans = Codec.JSON.readSpans(response.getBody().getBytes());
+ List serviceNamesNotFoundInZipkin = serviceNamesNotFoundInZipkin(spans);
+ List spanNamesNotFoundInZipkin = annotationsNotFoundInZipkin(spans);
+ log.info("The following services were not found in Zipkin {}", serviceNamesNotFoundInZipkin);
+ log.info("The following spans were not found in Zipkin {}", spanNamesNotFoundInZipkin);
+ then(serviceNamesNotFoundInZipkin).isEmpty();
+ then(spanNamesNotFoundInZipkin).isEmpty();
+ log.info("Zipkin tracing is working! Sleuth is working! Let's be happy!");
+ };
+ }
+
+ protected List serviceNamesNotFoundInZipkin(List spans) {
+ List serviceNamesFoundInAnnotations = spans.stream()
+ .filter(span -> span.annotations != null)
+ .map(span -> span.annotations)
+ .flatMap(Collection::stream)
+ .filter(span -> span.endpoint != null)
+ .map(annotation -> annotation.endpoint)
+ .map(endpoint -> endpoint.serviceName)
+ .distinct()
+ .collect(Collectors.toList());
+ List serviceNamesFoundInBinaryAnnotations = spans.stream()
+ .filter(span -> span.binaryAnnotations != null)
+ .map(span -> span.binaryAnnotations)
+ .flatMap(Collection::stream)
+ .filter(span -> span.endpoint != null)
+ .map(annotation -> annotation.endpoint)
+ .map(endpoint -> endpoint.serviceName)
+ .distinct()
+ .collect(Collectors.toList());
+ List names = new ArrayList<>();
+ names.addAll(serviceNamesFoundInAnnotations);
+ names.addAll(serviceNamesFoundInBinaryAnnotations);
+ return names.contains(getAppName()) ? Collections.EMPTY_LIST : names;
+ }
+
+ protected String getAppName() {
+ return "unknown";
+ }
+
+ protected List annotationsNotFoundInZipkin(List spans) {
+ String binaryAnnotationName = getRequiredBinaryAnnotationName();
+ Optional names = spans.stream()
+ .filter(span -> span.binaryAnnotations != null)
+ .map(span -> span.binaryAnnotations)
+ .flatMap(Collection::stream)
+ .filter(span -> span.endpoint != null)
+ .map(annotation -> annotation.key)
+ .filter(binaryAnnotationName::equals)
+ .findFirst();
+ return names.isPresent() ? Collections.EMPTY_LIST : Collections.singletonList(binaryAnnotationName);
+ }
+
+ protected String getRequiredBinaryAnnotationName() {
+ return "random-sleep-millis";
+ }
+
+ @Configuration
+ public static class Config {
+ @Bean
+ SpanCollector integrationTestSpanCollector() {
+ return new IntegrationTestSpanCollector();
+ }
+ }
+
+ @Configuration
+ @Slf4j
+ public static class ZipkinConfig {
+ @Bean
+ @SneakyThrows
+ public ScribeSpanCollector spanCollector(final ZipkinProperties zipkin) {
+ await().until(() -> {
+ try {
+ ZipkinConfig.this.getSpanCollector(zipkin);
+ } catch (Exception e) {
+ log.error("Exception occurred while trying to connect to zipkin [" + e.getCause() + "]");
+ throw new AssertionError(e);
+ }
+ });
+ return getSpanCollector(zipkin);
+ }
+
+ private ScribeSpanCollector getSpanCollector(ZipkinProperties zipkin) {
+ return new ScribeSpanCollector(getDockerURI().getHost(),
+ zipkin.getPort(), zipkin.getCollector());
+ }
+ }
+}
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/AbstractIntegrationTest.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/AbstractIntegrationTest.java
deleted file mode 100644
index 581ae5cd0..000000000
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/AbstractIntegrationTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2013-2015 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package tools;
-
-import com.github.kristofa.brave.EmptySpanCollectorMetricsHandler;
-import com.github.kristofa.brave.HttpSpanCollector;
-import com.github.kristofa.brave.SpanCollector;
-import com.github.kristofa.brave.SpanCollectorMetricsHandler;
-import com.jayway.awaitility.Awaitility;
-import com.jayway.awaitility.core.ConditionFactory;
-import java.net.URI;
-import lombok.SneakyThrows;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.cloud.sleuth.zipkin.ZipkinProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpMethod;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.RequestEntity;
-import org.springframework.http.ResponseEntity;
-import org.springframework.util.StringUtils;
-import org.springframework.web.client.RestTemplate;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.assertj.core.api.BDDAssertions.then;
-
-/**
- * @author Marcin Grzejszczak
- */
-@Slf4j
-public abstract class AbstractIntegrationTest {
-
- protected static int pollInterval = 1;
- protected static int timeout = 120;
- protected RestTemplate restTemplate = new AssertingRestTemplate();
-
- protected static ConditionFactory await() {
- return Awaitility.await().pollInterval(pollInterval, SECONDS).atMost(timeout, SECONDS);
- }
-
- protected long zipkinHashedTraceId(String string) {
- long h = 1125899906842597L;
- if (string == null) {
- return h;
- }
- int len = string.length();
-
- for (int i = 0; i < len; i++) {
- h = 31 * h + string.charAt(i);
- }
- return h;
- }
-
- String zipkinHashedHexStringTraceId(String traceId) {
- long hashedTraceId = zipkinHashedTraceId(traceId);
- return Long.toHexString(hashedTraceId);
- }
-
- protected static String getDockerUrl() {
- URI dockerUri = getDockerURI();
- if (StringUtils.isEmpty(dockerUri.getScheme())) {
- return "http://localhost";
- }
- return "http://" + dockerUri.getHost();
- }
-
- protected static URI getDockerURI() {
- String dockerHost = System.getenv("DOCKER_HOST");
- if (StringUtils.isEmpty(dockerHost)) {
- return URI.create("http://localhost");
- }
- return URI.create(dockerHost);
- }
-
- protected Runnable zipkinQueryServerIsUp() {
- return new Runnable() {
- @Override
- public void run() {
- ResponseEntity response = endpointToCheckZipkinQueryHealth();
- log.info("Response from the Zipkin query with current traces [{}]", response);
- then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
- log.info("Zipkin query server is up!");
- }
- };
- }
-
- protected ResponseEntity endpointToCheckZipkinQueryHealth() {
- URI uri = URI.create(getZipkinServicesQueryUrl());
- log.info("Sending request to the Zipkin query service [{}]", uri);
- return exchangeRequest(uri);
- }
-
- protected ResponseEntity checkStateOfTheTraceId(String traceId) {
- String hexTraceId = zipkinHashedHexStringTraceId(traceId);
- URI uri = URI.create(getZipkinTraceQueryUrl() + hexTraceId);
- log.info("Sending request to the Zipkin query service [{}]. Checking presence of trace id [{}] and its hex version [{}]", uri, traceId, hexTraceId);
- return exchangeRequest(uri);
- }
-
- protected ResponseEntity exchangeRequest(URI uri) {
- return restTemplate.exchange(
- new RequestEntity<>(new HttpHeaders(), HttpMethod.GET, uri), String.class
- );
- }
-
- protected String getZipkinTraceQueryUrl() {
- return getDockerUrl() + ":9411/api/v1/trace/";
- }
-
- protected String getZipkinServicesQueryUrl() {
- return getDockerUrl() + ":9411/api/v1/services";
- }
-
- @Configuration
- public static class Config {
- @Bean
- SpanCollector integrationTestSpanCollector() {
- return new IntegrationTestSpanCollector();
- }
- }
-
- @Configuration
- @Slf4j
- public static class ZipkinConfig {
- @Bean
- @SneakyThrows
- public SpanCollector spanCollector(final ZipkinProperties zipkin) {
- await().until(new Runnable() {
- @Override
- public void run() {
- try {
- ZipkinConfig.this.getSpanCollector(zipkin);
- } catch (Exception e) {
- log.error("Exception occurred while trying to connect to zipkin [" + e.getCause() + "]");
- throw new AssertionError(e);
- }
- }
- });
- return getSpanCollector(zipkin);
- }
-
- private SpanCollector getSpanCollector(ZipkinProperties zipkin) {
- String url = "http://" + getDockerURI().getHost() + ":" + zipkin.getPort();
- // TODO: parameterize this
- SpanCollectorMetricsHandler metrics = new EmptySpanCollectorMetricsHandler();
- return HttpSpanCollector.create(url, zipkin.getHttpConfig(), metrics);
- }
- }
-}
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/RequestSendingRunnable.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/RequestSendingRunnable.java
index e69ec0139..b16f73fc7 100644
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/RequestSendingRunnable.java
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-test-core/src/main/java/tools/RequestSendingRunnable.java
@@ -44,6 +44,7 @@ public class RequestSendingRunnable implements Runnable {
@Override
public void run() {
+ log.info("Sending the request to url [{}] with trace id in headers [{}]", url, traceId);
ResponseEntity responseEntity = restTemplate.exchange(requestWithTraceId(traceId), String.class);
then(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
log.info("Received the following response [{}]", responseEntity);
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/pom.xml
index 5597f4c05..459aa8e95 100644
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/pom.xml
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/pom.xml
@@ -49,6 +49,18 @@
org.springframework.cloud
spring-cloud-stream-binder-rabbit
+
+ com.github.kristofa
+ brave-spancollector-scribe
+
+
+ com.github.kristofa
+ brave-http
+
+
+ com.github.kristofa
+ brave-spring-web-servlet-interceptor
+
com.h2database
h2
@@ -75,6 +87,27 @@
spring-boot-starter-test
test
+
+ org.springframework.cloud
+ spring-cloud-sleuth-sample-test-core
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ org.testcontainers
+ docker-compose
+
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/java/integration/SampleApp.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/java/integration/SampleApp.java
new file mode 100644
index 000000000..fe6564130
--- /dev/null
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/java/integration/SampleApp.java
@@ -0,0 +1,111 @@
+package integration;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.connection.RabbitConnectionFactoryBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
+import org.springframework.cloud.sleuth.TraceManager;
+import org.springframework.cloud.sleuth.trace.TraceContextHolder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import tools.AbstractDockerIntegrationTest;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.util.Random;
+
+/**
+ * @author Marcin Grzejszczak
+ */
+@RestController
+@Slf4j
+public class SampleApp {
+
+ @Autowired
+ private TraceManager traceManager;
+
+ @SneakyThrows
+ @RequestMapping("/hi2")
+ public String hi2() {
+ log.info("I'm in the sample app");
+ final Random random = new Random();
+ int millis = random.nextInt(1000);
+ Thread.sleep(millis);
+ this.traceManager.addAnnotation("random-sleep-millis", String.valueOf(millis));
+ log.info("Current span is [{}]", TraceContextHolder.getCurrentSpan());
+ return "hi2";
+ }
+
+ @Configuration
+ @EnableAutoConfiguration
+ @Slf4j
+ public static class Config {
+
+ public static final int RABBITMQ_PORT = 5672;
+
+ @Bean SampleApp sampleApp() {
+ return new SampleApp();
+ }
+
+ @Bean
+ @SneakyThrows
+ ConnectionFactory connectionFactory() {
+ RabbitProperties config = rabbitProperties();
+ AbstractDockerIntegrationTest.await().until(() -> {
+ try {
+ ServerSocket serverSocket = new ServerSocket(RABBITMQ_PORT, 50,
+ InetAddress.getByName(AbstractDockerIntegrationTest.getDockerURI().getHost()));
+ serverSocket.close();
+ } catch (IOException e) {
+ log.info("RabbitMQ is up and running - proceeding");
+ return true;
+ }
+ log.warn("RabbitMQ has not started yet...");
+ return false;
+ });
+ RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();
+ if (config.getHost() != null) {
+ factory.setHost(config.getHost());
+ factory.setPort(config.getPort());
+ }
+ if (config.getUsername() != null) {
+ factory.setUsername(config.getUsername());
+ }
+ if (config.getPassword() != null) {
+ factory.setPassword(config.getPassword());
+ }
+ if (config.getVirtualHost() != null) {
+ factory.setVirtualHost(config.getVirtualHost());
+ }
+ if (config.getRequestedHeartbeat() != null) {
+ factory.setRequestedHeartbeat(config.getRequestedHeartbeat());
+ }
+ RabbitProperties.Ssl ssl = config.getSsl();
+ if (ssl.isEnabled()) {
+ factory.setUseSSL(true);
+ factory.setKeyStore(ssl.getKeyStore());
+ factory.setKeyStorePassphrase(ssl.getKeyStorePassword());
+ factory.setTrustStore(ssl.getTrustStore());
+ factory.setTrustStorePassphrase(ssl.getTrustStorePassword());
+ }
+ factory.afterPropertiesSet();
+ CachingConnectionFactory connectionFactory = new CachingConnectionFactory(
+ factory.getObject());
+ connectionFactory.setAddresses(config.getAddresses());
+ return connectionFactory;
+ }
+
+ RabbitProperties rabbitProperties() {
+ RabbitProperties rabbitProperties = new RabbitProperties();
+ rabbitProperties.setHost(AbstractDockerIntegrationTest.getDockerURI().getHost());
+ return rabbitProperties;
+ }
+ }
+}
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/java/integration/ZipkinStreamDockerTests.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/java/integration/ZipkinStreamDockerTests.java
new file mode 100644
index 000000000..cae4fce7c
--- /dev/null
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/java/integration/ZipkinStreamDockerTests.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package integration;
+
+import example.ZipkinStreamServerApplication;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.boot.test.WebIntegrationTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.JdkIdGenerator;
+import org.testcontainers.containers.DockerComposeContainer;
+import tools.AbstractDockerIntegrationTest;
+
+import java.io.File;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringApplicationConfiguration(classes = { SampleApp.Config.class,
+ AbstractDockerIntegrationTest.ZipkinConfig.class, ZipkinStreamServerApplication.class })
+@WebIntegrationTest()
+@Slf4j
+public class ZipkinStreamDockerTests extends AbstractDockerIntegrationTest {
+
+ private static int port = 9411;
+ private static String sampleAppUrl = "http://localhost:" + port;
+
+ @ClassRule
+ public static DockerComposeContainer environment =
+ new DockerComposeContainer(new File("src/test/resources/docker-compose.yml"))
+ .withExposedService("rabbitmq_1", 5672)
+ .withExposedService("rabbitmq_1", 15672)
+ .withExposedService("mysql_1", 3306);
+
+ @Test
+ @SneakyThrows
+ public void should_propagate_spans_to_zipkin() {
+ await().until(zipkinServerIsUp());
+ String traceId = new JdkIdGenerator().generateId().toString();
+
+ await().until(httpMessageWithTraceIdInHeadersIsSuccessfullySent(sampleAppUrl + "/hi2", traceId));
+
+ await().until(allSpansWereRegisteredInZipkinWithTraceIdEqualTo(traceId));
+ }
+
+ @Override
+ protected String getZipkinRootUrl() {
+ return "http://localhost";
+ }
+}
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/resources/docker-compose.yml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/resources/docker-compose.yml
new file mode 100644
index 000000000..819663b8a
--- /dev/null
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/resources/docker-compose.yml
@@ -0,0 +1,13 @@
+mysql:
+ image: mysql
+ ports:
+ - 3306:3306
+ environment:
+ - MYSQL_ROOT_PASSWORD=root
+ - MYSQL_DATABASE=test
+
+rabbitmq:
+ image: rabbitmq:management
+ ports:
+ - 5672:5672
+ - 15672:15672
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/resources/logback.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/resources/logback.xml
new file mode 100644
index 000000000..3cee99001
--- /dev/null
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/test/resources/logback.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/pom.xml
index 0b69d9ac8..62533c238 100644
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/pom.xml
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/pom.xml
@@ -100,6 +100,23 @@
${testcontainers.jackson.version}
compile
+
+ org.testcontainers
+ docker-compose
+ test
+
+
+ com.github.kristofa
+ brave-spancollector-scribe
+
+
+ com.github.kristofa
+ brave-http
+
+
+ com.github.kristofa
+ brave-spring-web-servlet-interceptor
+
diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/test/java/integration/ZipkinDockerTests.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/test/java/integration/ZipkinDockerTests.java
index 5722b7317..4366b4661 100644
--- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/test/java/integration/ZipkinDockerTests.java
+++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin/src/test/java/integration/ZipkinDockerTests.java
@@ -15,7 +15,6 @@
*/
package integration;
-import io.zipkin.Codec;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
@@ -24,28 +23,21 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.WebIntegrationTest;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.JdkIdGenerator;
import org.testcontainers.containers.DockerComposeContainer;
import sample.SampleZipkinApplication;
-import tools.AbstractIntegrationTest;
-import tools.RequestSendingRunnable;
+import tools.AbstractDockerIntegrationTest;
import java.io.File;
-import java.util.*;
-import java.util.stream.Collectors;
-
-import static org.assertj.core.api.BDDAssertions.then;
@RunWith(SpringJUnit4ClassRunner.class)
-@SpringApplicationConfiguration(classes = { AbstractIntegrationTest.ZipkinConfig.class, SampleZipkinApplication.class })
+@SpringApplicationConfiguration(classes = { AbstractDockerIntegrationTest.ZipkinConfig.class, SampleZipkinApplication.class })
@WebIntegrationTest
@TestPropertySource(properties="sample.zipkin.enabled=true")
@Slf4j
-public class ZipkinDockerTests extends AbstractIntegrationTest {
+public class ZipkinDockerTests extends AbstractDockerIntegrationTest {
private static final String APP_NAME = "testsleuthzipkin";
private static int port = 3380;
@@ -68,65 +60,13 @@ public class ZipkinDockerTests extends AbstractIntegrationTest {
public void should_propagate_spans_to_zipkin() {
String traceId = new JdkIdGenerator().generateId().toString();
- httpMessageWithTraceIdInHeadersIsSuccessfullySent(sampleAppUrl + "/hi2", traceId);
+ await().until(httpMessageWithTraceIdInHeadersIsSuccessfullySent(sampleAppUrl + "/hi2", traceId));
- await().until(() -> {
- allSpansWereRegisteredInZipkinWithTraceIdEqualTo(traceId);
- });
+ await().until(allSpansWereRegisteredInZipkinWithTraceIdEqualTo(traceId));
}
- private void allSpansWereRegisteredInZipkinWithTraceIdEqualTo(String traceId) {
- ResponseEntity response = checkStateOfTheTraceId(traceId);
- log.info("Response from the Zipkin query service about the trace id [{}] for trace with id [{}]", response, traceId);
- then(response.getStatusCode()).isEqualTo(HttpStatus.OK);
- then(response.hasBody()).isTrue();
- List spans = Codec.JSON.readSpans(response.getBody().getBytes());
- List serviceNamesNotFoundInZipkin = serviceNamesNotFoundInZipkin(spans);
- List spanNamesNotFoundInZipkin = annotationsNotFoundInZipkin(spans);
- log.info("The following services were not found in Zipkin {}", serviceNamesNotFoundInZipkin);
- log.info("The following spans were not found in Zipkin {}", spanNamesNotFoundInZipkin);
- then(serviceNamesNotFoundInZipkin).isEmpty();
- then(spanNamesNotFoundInZipkin).isEmpty();
- log.info("Zipkin tracing is working! Sleuth is working! Let's be happy!");
+ @Override
+ protected String getAppName() {
+ return APP_NAME;
}
-
- private List serviceNamesNotFoundInZipkin(List spans) {
- List serviceNamesFoundInAnnotations = spans.stream()
- .map(span -> span.annotations)
- .flatMap(Collection::stream)
- .filter(span -> span.endpoint != null)
- .map(annotation -> annotation.endpoint)
- .map(endpoint -> endpoint.serviceName)
- .distinct()
- .collect(Collectors.toList());
- List serviceNamesFoundInBinaryAnnotations = spans.stream()
- .map(span -> span.binaryAnnotations)
- .flatMap(Collection::stream)
- .filter(span -> span.endpoint != null)
- .map(annotation -> annotation.endpoint)
- .map(endpoint -> endpoint.serviceName)
- .distinct()
- .collect(Collectors.toList());
- List names = new ArrayList<>();
- names.addAll(serviceNamesFoundInAnnotations);
- names.addAll(serviceNamesFoundInBinaryAnnotations);
- return names.contains(APP_NAME) ? Collections.EMPTY_LIST : names;
- }
-
- private List annotationsNotFoundInZipkin(List spans) {
- String binaryAnnotationName = "random-sleep-millis";
- Optional names = spans.stream()
- .map(span -> span.binaryAnnotations)
- .flatMap(Collection::stream)
- .filter(span -> span.endpoint != null)
- .map(annotation -> annotation.key)
- .filter(binaryAnnotationName::equals)
- .findFirst();
- return names.isPresent() ? Collections.EMPTY_LIST : Collections.singletonList(binaryAnnotationName);
- }
-
- private void httpMessageWithTraceIdInHeadersIsSuccessfullySent(String endpoint, String traceId) {
- new RequestSendingRunnable(restTemplate, endpoint, traceId).run();
- }
-
}