diff --git a/spring-cloud-sleuth-dependencies/pom.xml b/spring-cloud-sleuth-dependencies/pom.xml index 7a56551dd2..2dedde5de6 100644 --- a/spring-cloud-sleuth-dependencies/pom.xml +++ b/spring-cloud-sleuth-dependencies/pom.xml @@ -14,7 +14,9 @@ spring-cloud-sleuth-dependencies Spring Cloud Sleuth Dependencies - 2.2.1 + + 2.2.0 + 2.2.1 1.1.2 2.1.3 @@ -73,7 +75,7 @@ io.zipkin.zipkin2 zipkin - ${zipkin.version} + ${zipkin2.version} io.zipkin.java diff --git a/spring-cloud-sleuth-samples/pom.xml b/spring-cloud-sleuth-samples/pom.xml index 1a18a656e2..c041b91291 100644 --- a/spring-cloud-sleuth-samples/pom.xml +++ b/spring-cloud-sleuth-samples/pom.xml @@ -54,21 +54,11 @@ spring-cloud-sleuth-sample-test-core ${project.version} - - io.zipkin.java - zipkin - 2.2.1 - io.zipkin.zipkin2 zipkin 2.2.1 - - io.zipkin.java - zipkin-server - 2.2.1 - diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/pom.xml index 62d0a3d703..a9506c6353 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/pom.xml +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/pom.xml @@ -68,7 +68,7 @@ org.springframework.cloud - spring-cloud-sleuth-zipkin + spring-cloud-sleuth-zipkin2 org.springframework.boot diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/src/main/java/sample/SampleFeignApplication.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/src/main/java/sample/SampleFeignApplication.java index 7b6eacb115..74c54a8559 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/src/main/java/sample/SampleFeignApplication.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-feign/src/main/java/sample/SampleFeignApplication.java @@ -22,10 +22,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.netflix.feign.EnableFeignClients; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; import org.springframework.context.annotation.Bean; -import zipkin.Span; +import zipkin2.Span; +import zipkin2.reporter.Reporter; /** * @author Spencer Gibb @@ -43,8 +43,8 @@ public static void main(String[] args) { // Use this for debugging (or if there is no Zipkin server running on port 9411) @Bean @ConditionalOnProperty(value = "sample.zipkin.enabled", havingValue = "false") - public ZipkinSpanReporter spanCollector() { - return new ZipkinSpanReporter() { + public Reporter spanReporter() { + return new Reporter() { @Override public void report(Span span) { logger.info(span); 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 5380ce6be1..7b36713e66 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 @@ -82,7 +82,7 @@ org.springframework.cloud - spring-cloud-sleuth-zipkin + spring-cloud-sleuth-zipkin2 org.springframework.boot diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/IntegrationTestZipkinSpanReporter.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/IntegrationTestZipkinSpanReporter.java index a8774e550d..dee6a7df35 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/IntegrationTestZipkinSpanReporter.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/IntegrationTestZipkinSpanReporter.java @@ -20,16 +20,16 @@ import java.util.List; import org.apache.commons.logging.Log; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; -import zipkin.Span; +import zipkin2.Span; +import zipkin2.reporter.Reporter; /** * Span Collector that logs spans and adds Spans to a list * * @author Marcin Grzejszczak */ -public class IntegrationTestZipkinSpanReporter implements ZipkinSpanReporter { +public class IntegrationTestZipkinSpanReporter implements Reporter { private static final Log log = org.apache.commons.logging.LogFactory .getLog(IntegrationTestZipkinSpanReporter.class); diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationTests.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationTests.java index 611492637c..17fb1f0e25 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationTests.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-messaging/src/test/java/integration/MessagingApplicationTests.java @@ -15,8 +15,6 @@ */ package integration; -import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Random; @@ -27,7 +25,6 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.annotation.DirtiesContext; @@ -37,8 +34,8 @@ import integration.MessagingApplicationTests.IntegrationSpanCollectorConfig; import sample.SampleMessagingApplication; import tools.AbstractIntegrationTest; -import zipkin.Constants; -import zipkin.Span; +import zipkin2.Span; +import zipkin2.reporter.Reporter; import static java.util.concurrent.TimeUnit.SECONDS; import static org.assertj.core.api.BDDAssertions.then; @@ -81,7 +78,7 @@ public void should_have_passed_trace_id_and_generate_new_span_id_when_message_is httpMessageWithTraceIdInHeadersIsSuccessfullySent(sampleAppUrl + "/", traceId, spanId).run() ); - await().atMost(5, SECONDS).untilAsserted(() -> { + await().atMost(10, SECONDS).untilAsserted(() -> { thenAllSpansHaveTraceIdEqualTo(traceId); thenTheSpansHaveProperParentStructure(); }); @@ -97,36 +94,36 @@ public void should_have_passed_trace_id_with_annotations_in_async_thread_when_me await().atMost(5, SECONDS).untilAsserted(() -> { thenAllSpansHaveTraceIdEqualTo(traceId); - thenThereIsAtLeastOneBinaryAnnotationWithKey("background-sleep-millis"); + thenThereIsAtLeastOneTagWithKey("background-sleep-millis"); }); } - private void thenThereIsAtLeastOneBinaryAnnotationWithKey(String binaryAnnotationKey) { + private void thenThereIsAtLeastOneTagWithKey(String key) { then(this.integrationTestSpanCollector.hashedSpans.stream() - .map(s -> s.binaryAnnotations) - .flatMap(Collection::stream) - .anyMatch(b -> b.key.equals(binaryAnnotationKey))).isTrue(); + .map(Span::tags) + .flatMap(m -> m.keySet().stream()) + .anyMatch(b -> b.equals(key))).isTrue(); } private void thenAllSpansHaveTraceIdEqualTo(long traceId) { + String traceIdHex = Long.toHexString(traceId); then(this.integrationTestSpanCollector.hashedSpans.stream() - .allMatch(span -> span.traceId == traceId)).describedAs("All spans have same trace id").isTrue(); + .allMatch(span -> span.traceId().equals(traceIdHex))).describedAs("All spans have same trace id").isTrue(); } private void thenTheSpansHaveProperParentStructure() { Optional firstHttpSpan = findFirstHttpRequestSpan(); List eventSpans = findAllEventRelatedSpans(); - Optional eventSentSpan = findSpanWithAnnotation(Constants.SERVER_SEND); - Optional eventReceivedSpan = findSpanWithAnnotation(Constants.CLIENT_RECV); + Optional eventSentSpan = findSpanWithKind(Span.Kind.SERVER); + Optional eventReceivedSpan = findSpanWithKind(Span.Kind.CLIENT); Optional lastHttpSpansParent = findLastHttpSpansParent(); // "http:/parent/" -> "message:messages" -> "http:/foo" (CS + CR) -> "http:/foo" (SS) - Collections.sort(this.integrationTestSpanCollector.hashedSpans); thenAllSpansArePresent(firstHttpSpan, eventSpans, lastHttpSpansParent, eventSentSpan, eventReceivedSpan); then(this.integrationTestSpanCollector.hashedSpans).as("There were 4 spans").hasSize(4); log.info("Checking the parent child structure"); List> parentChild = this.integrationTestSpanCollector.hashedSpans.stream() - .filter(span -> span.parentId != null) - .map(span -> this.integrationTestSpanCollector.hashedSpans.stream().filter(span1 -> span1.id == span.parentId).findAny() + .filter(span -> span.parentId() != null) + .map(span -> this.integrationTestSpanCollector.hashedSpans.stream().filter(span1 -> span1.id().equals(span.parentId())).findAny() ).collect(Collectors.toList()); log.info("List of parents and children " + parentChild); then(parentChild.stream().allMatch(Optional::isPresent)).isTrue(); @@ -134,27 +131,26 @@ private void thenTheSpansHaveProperParentStructure() { private Optional findLastHttpSpansParent() { return this.integrationTestSpanCollector.hashedSpans.stream() - .filter(span -> "http:/foo".equals(span.name) && !span.annotations.isEmpty()).findFirst(); + .filter(span -> "http:/foo".equals(span.name()) && span.kind() != null).findFirst(); } - private Optional findSpanWithAnnotation(String annotationName) { + private Optional findSpanWithKind(Span.Kind kind) { return this.integrationTestSpanCollector.hashedSpans.stream() - .filter(span -> span.annotations.stream().filter(annotation -> annotationName - .equals(annotation.value)).findFirst().isPresent()) + .filter(span -> kind.equals(span.kind())) .findFirst(); } private List findAllEventRelatedSpans() { return this.integrationTestSpanCollector.hashedSpans.stream() - .filter(span -> "message:messages".equals(span.name) && span.parentId != null).collect( + .filter(span -> "message:messages".equals(span.name()) && span.parentId() != null).collect( Collectors.toList()); } private Optional findFirstHttpRequestSpan() { return this.integrationTestSpanCollector.hashedSpans.stream() // home is the name of the method - .filter(span -> span.binaryAnnotations.stream() - .anyMatch(binaryAnnotation -> new String(binaryAnnotation.value).equals("home"))).findFirst(); + .filter(span -> span.tags().values().stream() + .anyMatch("home"::equals)).findFirst(); } private void thenAllSpansArePresent(Optional firstHttpSpan, @@ -178,9 +174,8 @@ private void thenAllSpansArePresent(Optional firstHttpSpan, @Configuration public static class IntegrationSpanCollectorConfig { @Bean - ZipkinSpanReporter integrationTestZipkinSpanReporter() { + Reporter integrationTestZipkinSpanReporter() { return new IntegrationTestZipkinSpanReporter(); } } - } diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/pom.xml index 13e63c2bca..0d7c1bbbc7 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/pom.xml +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/pom.xml @@ -70,7 +70,7 @@ org.springframework.cloud - spring-cloud-sleuth-zipkin + spring-cloud-sleuth-zipkin2 org.springframework.boot diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/java/sample/SampleRibbonApplication.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/java/sample/SampleRibbonApplication.java index ff4a0c18b1..99850932a5 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/java/sample/SampleRibbonApplication.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-ribbon/src/main/java/sample/SampleRibbonApplication.java @@ -22,12 +22,12 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.web.client.RestTemplate; -import zipkin.Span; +import zipkin2.Span; +import zipkin2.reporter.Reporter; /** * @author Spencer Gibb @@ -51,8 +51,8 @@ public RestTemplate restTemplate() { // Use this for debugging (or if there is no Zipkin server running on port 9411) @Bean @ConditionalOnProperty(value = "sample.zipkin.enabled", havingValue = "false") - public ZipkinSpanReporter spanCollector() { - return new ZipkinSpanReporter() { + public Reporter spanReporter() { + return new Reporter() { @Override public void report(Span span) { logger.info(span); 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 8aa15f999b..4f9aae2c66 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 @@ -105,7 +105,7 @@ compile - io.zipkin.java + io.zipkin.zipkin2 zipkin 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 index 69c5449367..d0a73c0e9e 100644 --- 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 @@ -15,18 +15,7 @@ */ package tools; -import zipkin.Codec; -import zipkin.Span; - import java.lang.invoke.MethodHandles; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.awaitility.Awaitility; @@ -34,15 +23,9 @@ import org.junit.After; import org.junit.Before; import org.springframework.cloud.sleuth.trace.IntegrationTestSpanContextHolder; -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.web.client.RestTemplate; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.assertj.core.api.BDDAssertions.then; /** * @author Marcin Grzejszczak @@ -65,57 +48,6 @@ public void clearSpanAfter() { IntegrationTestSpanContextHolder.removeCurrentSpan(); } - public static ConditionFactory await() { - return Awaitility.await().pollInterval(POLL_INTERVAL, SECONDS).atMost(TIMEOUT, SECONDS); - } - - protected Runnable zipkinServerIsUp() { - return checkServerHealth("Zipkin Stream Server", this::endpointToCheckZipkinServerHealth); - } - - protected Runnable checkServerHealth(String appName, RequestExchanger requestExchanger) { - return () -> { - ResponseEntity response = requestExchanger.exchange(); - log.info(String.format("Response from the [%s] health endpoint is [%s]", appName, response)); - then(response.getStatusCode()).isEqualTo(HttpStatus.OK); - log.info(String.format("[%s] is up!", appName)); - }; - } - - private interface RequestExchanger { - ResponseEntity exchange(); - } - - protected ResponseEntity endpointToCheckZipkinServerHealth() { - URI uri = URI.create("http://localhost:" +getZipkinServerPort()+"/health"); - log.info(String.format("Sending request to the Zipkin Server [%s]", uri)); - return exchangeRequest(uri); - } - - protected int getZipkinServerPort() { - return 9411; - } - - protected ResponseEntity checkStateOfTheTraceId(long traceId) { - URI uri = URI.create(getZipkinTraceQueryUrl() + Long.toHexString(traceId)); - log.info(String.format("Sending request to the Zipkin query service [%s]. " - + "Checking presence of trace id [%d]", uri, traceId)); - return exchangeRequest(uri); - } - - protected ResponseEntity exchangeRequest(URI uri) { - return this.restTemplate.exchange( - new RequestEntity<>(new HttpHeaders(), HttpMethod.GET, uri), String.class - ); - } - - protected String getZipkinTraceQueryUrl() { - return "http://localhost:"+getZipkinServerPort()+"/api/v1/trace/"; - } - - protected String getZipkinServicesQueryUrl() { - return "http://localhost:"+getZipkinServerPort()+"/api/v1/services"; - } protected Runnable httpMessageWithTraceIdInHeadersIsSuccessfullySent(String endpoint, long traceId) { return new RequestSendingRunnable(this.restTemplate, endpoint, traceId, null); @@ -125,68 +57,7 @@ protected Runnable httpMessageWithTraceIdInHeadersIsSuccessfullySent(String endp return new RequestSendingRunnable(this.restTemplate, endpoint, traceId, spanId); } - protected Runnable allSpansWereRegisteredInZipkinWithTraceIdEqualTo(long traceId) { - return () -> { - ResponseEntity response = checkStateOfTheTraceId(traceId); - log.info(String.format("Response from the Zipkin query service about the " - + "trace id [%s] for trace with id [%d]", 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(String.format("The following services were not found in Zipkin [%s]", serviceNamesNotFoundInZipkin)); - log.info(String.format("The following annotations were not found in Zipkin [%s]", 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.emptyList() : 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.emptyList() : Collections.singletonList(binaryAnnotationName); - } - - protected String getRequiredBinaryAnnotationName() { - return "random-sleep-millis"; + public static ConditionFactory await() { + return Awaitility.await().pollInterval(POLL_INTERVAL, SECONDS).atMost(TIMEOUT, SECONDS); } - } diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-websocket/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-websocket/pom.xml index 1720e7335f..e6213b62c8 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-websocket/pom.xml +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-websocket/pom.xml @@ -82,7 +82,7 @@ org.springframework.cloud - spring-cloud-sleuth-zipkin + spring-cloud-sleuth-zipkin2 org.springframework.boot diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/pom.xml b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/pom.xml index 776b0fd75b..46f2afc534 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/pom.xml +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/pom.xml @@ -97,20 +97,9 @@ spring-cloud-sleuth-sample-test-core test - - io.zipkin.java - zipkin-server - test - - - io.zipkin.java - zipkin-junit - test - - com.squareup.okhttp3 - okhttp + mockwebserver 3.9.0 test diff --git a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/src/test/java/integration/ZipkinTests.java b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/src/test/java/integration/ZipkinTests.java index fbbf8e9599..2d8e3f9632 100644 --- a/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/src/test/java/integration/ZipkinTests.java +++ b/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2/src/test/java/integration/ZipkinTests.java @@ -16,10 +16,17 @@ package integration; import integration.ZipkinTests.WaitUntilZipkinIsUpConfig; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; import sample.SampleZipkinApplication; import tools.AbstractIntegrationTest; -import zipkin.junit.ZipkinRule; -import zipkin.server.EnableZipkinServer; import java.net.URI; import java.util.Random; @@ -29,8 +36,6 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.sleuth.zipkin2.ZipkinProperties; import org.springframework.context.annotation.Bean; @@ -38,16 +43,18 @@ import org.springframework.context.annotation.Primary; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import zipkin2.Span; +import zipkin2.codec.SpanBytesDecoder; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.assertj.core.api.BDDAssertions.then; @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = { WaitUntilZipkinIsUpConfig.class, SampleZipkinApplication.class }, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @TestPropertySource(properties = {"sample.zipkin.enabled=true"}) public class ZipkinTests extends AbstractIntegrationTest { - - @ClassRule public static final ZipkinRule zipkin = new ZipkinRule(); + @ClassRule public static final MockWebServer zipkin = new MockWebServer(); private static final String APP_NAME = "testsleuthzipkin"; @Value("${local.server.port}") @@ -55,7 +62,7 @@ public class ZipkinTests extends AbstractIntegrationTest { private String sampleAppUrl = "http://localhost:" + this.port; @Autowired ZipkinProperties zipkinProperties; - @Override protected int getZipkinServerPort() { + int getZipkinServerPort() { return getPortFromProps(); } @@ -64,21 +71,20 @@ private int getPortFromProps() { } @Test - public void should_propagate_spans_to_zipkin() { + public void should_propagate_spans_to_zipkin() throws Exception { + zipkin.enqueue(new MockResponse()); + long traceId = new Random().nextLong(); await().atMost(10, SECONDS).untilAsserted(() -> httpMessageWithTraceIdInHeadersIsSuccessfullySent( - this.sampleAppUrl + "/hi2", traceId).run() + this.sampleAppUrl + "/hi2", traceId).run() ); - await().atMost(10, SECONDS).untilAsserted(() -> - allSpansWereRegisteredInZipkinWithTraceIdEqualTo(traceId).run() - ); + spansSentToZipkin(zipkin, traceId); } - @Override - protected String getAppName() { + String getAppName() { return APP_NAME; } @@ -89,16 +95,63 @@ public static class WaitUntilZipkinIsUpConfig { @Primary ZipkinProperties testZipkinProperties() { ZipkinProperties zipkinProperties = new ZipkinProperties(); - zipkinProperties.setBaseUrl(zipkin.httpUrl()); + zipkinProperties.setBaseUrl(zipkin.url("/").toString()); return zipkinProperties; } } - @SpringBootApplication - @EnableZipkinServer - protected static class ZipkinServer { - public static void main(String[] args) { - SpringApplication.run(ZipkinServer.class, args); - } + void spansSentToZipkin(MockWebServer zipkin, long traceId) + throws InterruptedException { + RecordedRequest request = zipkin.takeRequest(); + List spans = SpanBytesDecoder.JSON_V2.decodeList(request.getBody().readByteArray()); + List traceIdsNotFoundInZipkin = traceIdsNotFoundInZipkin(spans, traceId); + List serviceNamesNotFoundInZipkin = serviceNamesNotFoundInZipkin(spans); + List tagsNotFoundInZipkin = hasRequiredTag(spans); + log.info(String.format("The following trace IDs were not found in Zipkin [%s]", traceIdsNotFoundInZipkin)); + log.info(String.format("The following services were not found in Zipkin [%s]", serviceNamesNotFoundInZipkin)); + log.info(String.format("The following tags were not found in Zipkin [%s]", tagsNotFoundInZipkin)); + then(traceIdsNotFoundInZipkin).isEmpty(); + then(serviceNamesNotFoundInZipkin).isEmpty(); + then(tagsNotFoundInZipkin).isEmpty(); + log.info("Zipkin tracing is working! Sleuth is working! Let's be happy!"); + } + + List traceIdsNotFoundInZipkin(List spans, long traceId) { + String traceIdString = Long.toHexString(traceId); + Optional traceIds = spans.stream() + .map(Span::traceId) + .filter(traceIdString::equals) + .findFirst(); + return traceIds.isPresent() ? Collections.emptyList() : Collections.singletonList(traceIdString); + } + + List serviceNamesNotFoundInZipkin(List spans) { + List localServiceNames = spans.stream() + .map(Span::localServiceName) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + List remoteServiceNames = spans.stream() + .map(Span::remoteServiceName) + .filter(Objects::nonNull) + .distinct() + .collect(Collectors.toList()); + List names = new ArrayList<>(); + names.addAll(localServiceNames); + names.addAll(remoteServiceNames); + return names.contains(getAppName()) ? Collections.emptyList() : names; + } + + List hasRequiredTag(List spans) { + String key = getRequiredTagKey(); + Optional keys = spans.stream() + .flatMap(span -> span.tags().keySet().stream()) + .filter(key::equals) + .findFirst(); + return keys.isPresent() ? Collections.emptyList() : Collections.singletonList(key); + } + + String getRequiredTagKey() { + return "random-sleep-millis"; } } diff --git a/spring-cloud-sleuth-zipkin/pom.xml b/spring-cloud-sleuth-zipkin/pom.xml index dd5e7561cd..5d5baf63ea 100644 --- a/spring-cloud-sleuth-zipkin/pom.xml +++ b/spring-cloud-sleuth-zipkin/pom.xml @@ -69,6 +69,10 @@ io.zipkin.java zipkin + + io.zipkin.zipkin2 + zipkin + io.zipkin.reporter zipkin-reporter diff --git a/spring-cloud-sleuth-zipkin2/pom.xml b/spring-cloud-sleuth-zipkin2/pom.xml index 7266dc776a..bcda3ecef9 100644 --- a/spring-cloud-sleuth-zipkin2/pom.xml +++ b/spring-cloud-sleuth-zipkin2/pom.xml @@ -106,23 +106,11 @@ assertj-core test - - io.zipkin.java - zipkin-junit - test - org.awaitility awaitility test - - - com.squareup.okhttp3 - okhttp - 3.9.0 - test - com.squareup.okhttp3 mockwebserver diff --git a/spring-cloud-sleuth-zipkin2/src/test/java/org/springframework/cloud/sleuth/zipkin2/ZipkinDiscoveryClientTests.java b/spring-cloud-sleuth-zipkin2/src/test/java/org/springframework/cloud/sleuth/zipkin2/ZipkinDiscoveryClientTests.java index 9749e6929e..b91af08f9a 100644 --- a/spring-cloud-sleuth-zipkin2/src/test/java/org/springframework/cloud/sleuth/zipkin2/ZipkinDiscoveryClientTests.java +++ b/spring-cloud-sleuth-zipkin2/src/test/java/org/springframework/cloud/sleuth/zipkin2/ZipkinDiscoveryClientTests.java @@ -1,14 +1,12 @@ package org.springframework.cloud.sleuth.zipkin2; import static org.assertj.core.api.BDDAssertions.then; -import static org.springframework.cloud.sleuth.zipkin2.ZipkinDiscoveryClientTests.ZIPKIN_RULE; import java.io.IOException; import java.net.URI; -import java.util.Collections; -import java.util.List; import java.util.Map; +import okhttp3.mockwebserver.MockWebServer; import org.awaitility.Awaitility; import org.junit.ClassRule; import org.junit.Test; @@ -17,7 +15,6 @@ 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.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest; import org.springframework.cloud.sleuth.Span; @@ -26,8 +23,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.test.context.junit4.SpringRunner; -import zipkin.junit.ZipkinRule; - @RunWith(SpringRunner.class) @SpringBootTest(classes = ZipkinDiscoveryClientTests.Config.class, properties = { "spring.zipkin.baseUrl=http://zipkin/", @@ -35,7 +30,7 @@ }) public class ZipkinDiscoveryClientTests { - @ClassRule public static ZipkinRule ZIPKIN_RULE = new ZipkinRule(); + @ClassRule public static MockWebServer ZIPKIN_RULE = new MockWebServer(); @Autowired SpanReporter spanReporter; @@ -46,7 +41,7 @@ public void shouldUseDiscoveryClientToFindZipkinUrlIfPresent() throws Exception this.spanReporter.report(span); - Awaitility.await().untilAsserted(() -> then(ZIPKIN_RULE.httpRequestCount()).isGreaterThan(0)); + Awaitility.await().untilAsserted(() -> then(ZIPKIN_RULE.getRequestCount()).isGreaterThan(0)); } @Configuration @@ -85,7 +80,7 @@ public String getHost() { @Override public int getPort() { - return URI.create(ZIPKIN_RULE.httpUrl()).getPort(); + return ZIPKIN_RULE.url("/").port(); } @Override @@ -95,7 +90,7 @@ public boolean isSecure() { @Override public URI getUri() { - return URI.create(ZIPKIN_RULE.httpUrl()); + return ZIPKIN_RULE.url("/").uri(); } @Override