Misaligns Zipkin v1 from sharing the same version number as v2 (#760)

This does two things: ensures samples don't use Zipkin v1 in any way,
and misaligns the version numbers of zipkin v1 and zipkin v2 apis.

This is an attempt to walk around the gradle plugin issue, which only
exists when someone is using both versions of zipkin.

See https://github.com/spring-projects/spring-boot/issues/10778
This commit is contained in:
Adrian Cole
2017-10-27 17:29:45 +03:00
committed by GitHub
parent 08093b0a6e
commit bfe15ab0cd
17 changed files with 127 additions and 240 deletions

View File

@@ -14,7 +14,9 @@
<name>spring-cloud-sleuth-dependencies</name>
<description>Spring Cloud Sleuth Dependencies</description>
<properties>
<zipkin.version>2.2.1</zipkin.version>
<!-- misaligned intentionally https://github.com/spring-projects/spring-boot/issues/10778-->
<zipkin.version>2.2.0</zipkin.version>
<zipkin2.version>2.2.1</zipkin2.version>
<zipkin-reporter.version>1.1.2</zipkin-reporter.version>
<zipkin-reporter2.version>2.1.3</zipkin-reporter2.version>
</properties>
@@ -73,7 +75,7 @@
<dependency>
<groupId>io.zipkin.zipkin2</groupId>
<artifactId>zipkin</artifactId>
<version>${zipkin.version}</version>
<version>${zipkin2.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>

View File

@@ -54,21 +54,11 @@
<artifactId>spring-cloud-sleuth-sample-test-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>io.zipkin.zipkin2</groupId>
<artifactId>zipkin</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@@ -68,7 +68,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<artifactId>spring-cloud-sleuth-zipkin2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -22,10 +22,10 @@ import org.springframework.boot.SpringApplication;
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 class SampleFeignApplication {
// 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<Span> spanReporter() {
return new Reporter<Span>() {
@Override
public void report(Span span) {
logger.info(span);

View File

@@ -82,7 +82,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<artifactId>spring-cloud-sleuth-zipkin2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -20,16 +20,16 @@ import java.util.LinkedList;
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<Span> {
private static final Log log = org.apache.commons.logging.LogFactory
.getLog(IntegrationTestZipkinSpanReporter.class);

View File

@@ -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.Test;
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 org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
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 class MessagingApplicationTests extends AbstractIntegrationTest {
httpMessageWithTraceIdInHeadersIsSuccessfullySent(sampleAppUrl + "/", traceId, spanId).run()
);
await().atMost(5, SECONDS).untilAsserted(() -> {
await().atMost(10, SECONDS).untilAsserted(() -> {
thenAllSpansHaveTraceIdEqualTo(traceId);
thenTheSpansHaveProperParentStructure();
});
@@ -97,36 +94,36 @@ public class MessagingApplicationTests extends AbstractIntegrationTest {
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<Span> firstHttpSpan = findFirstHttpRequestSpan();
List<Span> eventSpans = findAllEventRelatedSpans();
Optional<Span> eventSentSpan = findSpanWithAnnotation(Constants.SERVER_SEND);
Optional<Span> eventReceivedSpan = findSpanWithAnnotation(Constants.CLIENT_RECV);
Optional<Span> eventSentSpan = findSpanWithKind(Span.Kind.SERVER);
Optional<Span> eventReceivedSpan = findSpanWithKind(Span.Kind.CLIENT);
Optional<Span> 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<Optional<Span>> 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 @@ public class MessagingApplicationTests extends AbstractIntegrationTest {
private Optional<Span> 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<Span> findSpanWithAnnotation(String annotationName) {
private Optional<Span> 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<Span> 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<Span> 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<Span> firstHttpSpan,
@@ -178,9 +174,8 @@ public class MessagingApplicationTests extends AbstractIntegrationTest {
@Configuration
public static class IntegrationSpanCollectorConfig {
@Bean
ZipkinSpanReporter integrationTestZipkinSpanReporter() {
Reporter<Span> integrationTestZipkinSpanReporter() {
return new IntegrationTestZipkinSpanReporter();
}
}
}

View File

@@ -70,7 +70,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<artifactId>spring-cloud-sleuth-zipkin2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -22,12 +22,12 @@ import org.springframework.boot.SpringApplication;
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 class SampleRibbonApplication {
// 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<Span> spanReporter() {
return new Reporter<Span>() {
@Override
public void report(Span span) {
logger.info(span);

View File

@@ -105,7 +105,7 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<groupId>io.zipkin.zipkin2</groupId>
<artifactId>zipkin</artifactId>
</dependency>
</dependencies>

View File

@@ -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.awaitility.core.ConditionFactory;
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 abstract class AbstractIntegrationTest {
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<String> 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<String> exchange();
}
protected ResponseEntity<String> 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<String> 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<String> 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 @@ public abstract class AbstractIntegrationTest {
return new RequestSendingRunnable(this.restTemplate, endpoint, traceId, spanId);
}
protected Runnable allSpansWereRegisteredInZipkinWithTraceIdEqualTo(long traceId) {
return () -> {
ResponseEntity<String> 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<Span> spans = Codec.JSON.readSpans(response.getBody().getBytes());
List<String> serviceNamesNotFoundInZipkin = serviceNamesNotFoundInZipkin(spans);
List<String> 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!");
};
public static ConditionFactory await() {
return Awaitility.await().pollInterval(POLL_INTERVAL, SECONDS).atMost(TIMEOUT, SECONDS);
}
protected List<String> serviceNamesNotFoundInZipkin(List<zipkin.Span> spans) {
List<String> 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<String> 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<String> names = new ArrayList<>();
names.addAll(serviceNamesFoundInAnnotations);
names.addAll(serviceNamesFoundInBinaryAnnotations);
return names.contains(getAppName()) ? Collections.emptyList() : names;
}
protected String getAppName() {
return "unknown";
}
protected List<String> annotationsNotFoundInZipkin(List<zipkin.Span> spans) {
String binaryAnnotationName = getRequiredBinaryAnnotationName();
Optional<String> 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";
}
}

View File

@@ -82,7 +82,7 @@
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<artifactId>spring-cloud-sleuth-zipkin2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@@ -97,20 +97,9 @@
<artifactId>spring-cloud-sleuth-sample-test-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-junit</artifactId>
<scope>test</scope>
</dependency>
<!-- otherwise spring boot's version of okhttp kicks zipkin-junit's deps out of alignment -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<artifactId>mockwebserver</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>

View File

@@ -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.Test;
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.Configuration;
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 @@ public class ZipkinTests extends AbstractIntegrationTest {
}
@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 class ZipkinTests extends AbstractIntegrationTest {
@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<Span> spans = SpanBytesDecoder.JSON_V2.decodeList(request.getBody().readByteArray());
List<String> traceIdsNotFoundInZipkin = traceIdsNotFoundInZipkin(spans, traceId);
List<String> serviceNamesNotFoundInZipkin = serviceNamesNotFoundInZipkin(spans);
List<String> 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<String> traceIdsNotFoundInZipkin(List<Span> spans, long traceId) {
String traceIdString = Long.toHexString(traceId);
Optional<String> traceIds = spans.stream()
.map(Span::traceId)
.filter(traceIdString::equals)
.findFirst();
return traceIds.isPresent() ? Collections.emptyList() : Collections.singletonList(traceIdString);
}
List<String> serviceNamesNotFoundInZipkin(List<Span> spans) {
List<String> localServiceNames = spans.stream()
.map(Span::localServiceName)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
List<String> remoteServiceNames = spans.stream()
.map(Span::remoteServiceName)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
List<String> names = new ArrayList<>();
names.addAll(localServiceNames);
names.addAll(remoteServiceNames);
return names.contains(getAppName()) ? Collections.emptyList() : names;
}
List<String> hasRequiredTag(List<Span> spans) {
String key = getRequiredTagKey();
Optional<String> 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";
}
}

View File

@@ -69,6 +69,10 @@
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.zipkin2</groupId>
<artifactId>zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter</groupId>
<artifactId>zipkin-reporter</artifactId>

View File

@@ -106,23 +106,11 @@
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<!-- otherwise spring boot's version of okhttp kicks zipkin-junit's deps out of alignment -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>

View File

@@ -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.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.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.Bean;
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 @@ import zipkin.junit.ZipkinRule;
})
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 class ZipkinDiscoveryClientTests {
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 class ZipkinDiscoveryClientTests {
@Override
public int getPort() {
return URI.create(ZIPKIN_RULE.httpUrl()).getPort();
return ZIPKIN_RULE.url("/").port();
}
@Override
@@ -95,7 +90,7 @@ public class ZipkinDiscoveryClientTests {
@Override
public URI getUri() {
return URI.create(ZIPKIN_RULE.httpUrl());
return ZIPKIN_RULE.url("/").uri();
}
@Override