diff --git a/spring-cloud-sleuth-core/pom.xml b/spring-cloud-sleuth-core/pom.xml index cff5f2c94..f7e1dad27 100644 --- a/spring-cloud-sleuth-core/pom.xml +++ b/spring-cloud-sleuth-core/pom.xml @@ -36,6 +36,10 @@ spring-boot-starter-actuator true + + org.springframework.cloud + spring-cloud-commons + org.springframework.cloud spring-cloud-starter-feign diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java index 31574f18e..4f793a3f1 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Span.java @@ -134,6 +134,11 @@ public class Span { */ public static final String SPAN_PEER_SERVICE_TAG_NAME = "peer.service"; + /** + * ID of the instance from which the span was originated. + */ + public static final String INSTANCEID = "spring.instance_id"; + private final long begin; private long end = 0; private final String name; diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/trace/DefaultTracerTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/trace/DefaultTracerTests.java index 74058665e..a17ef1959 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/trace/DefaultTracerTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/trace/DefaultTracerTests.java @@ -183,6 +183,7 @@ public class DefaultTracerTests { then(span).hasATag("key", "value").hasLoggedAnEvent("event"); then(continuedSpan).hasATag("key", "value").hasLoggedAnEvent("event"); then(span).isEqualTo(continuedSpan); + tracer.close(span); } private Span assertSpan(List spans, Long parentId, String name) { diff --git a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java index 5ad57ba26..cd71a167a 100644 --- a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java +++ b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/SleuthStreamAutoConfiguration.java @@ -37,6 +37,7 @@ import org.springframework.cloud.stream.config.ChannelBindingAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; +import org.springframework.core.env.Environment; import org.springframework.integration.config.GlobalChannelInterceptor; import org.springframework.integration.scheduling.PollerMetadata; import org.springframework.messaging.support.ChannelInterceptor; @@ -76,8 +77,8 @@ public class SleuthStreamAutoConfiguration { @Bean @ConditionalOnMissingBean public StreamSpanReporter sleuthStreamSpanReporter(HostLocator endpointLocator, - SpanMetricReporter spanMetricReporter) { - return new StreamSpanReporter(endpointLocator, spanMetricReporter); + SpanMetricReporter spanMetricReporter, Environment environment) { + return new StreamSpanReporter(endpointLocator, spanMetricReporter, environment); } @Bean(name = StreamSpanReporter.POLLER) diff --git a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/StreamSpanReporter.java b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/StreamSpanReporter.java index 3ddcbeade..82199b541 100644 --- a/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/StreamSpanReporter.java +++ b/spring-cloud-sleuth-stream/src/main/java/org/springframework/cloud/sleuth/stream/StreamSpanReporter.java @@ -17,17 +17,20 @@ package org.springframework.cloud.sleuth.stream; import java.lang.invoke.MethodHandles; +import java.util.Arrays; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; -import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.cloud.commons.util.IdUtils; +import org.springframework.cloud.sleuth.Log; import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.SpanReporter; import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.core.env.Environment; import org.springframework.integration.annotation.InboundChannelAdapter; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.Poller; @@ -41,7 +44,11 @@ import org.springframework.integration.annotation.Poller; @MessageEndpoint public class StreamSpanReporter implements SpanReporter { - private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); + private static final org.apache.commons.logging.Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); + + private static final List RPC_EVENTS = Arrays.asList( + Span.CLIENT_RECV, Span.CLIENT_SEND, Span.SERVER_RECV, Span.SERVER_SEND + ); /** * Bean name for the @@ -53,10 +60,19 @@ public class StreamSpanReporter implements SpanReporter { private BlockingQueue queue = new LinkedBlockingQueue<>(1000); private final HostLocator endpointLocator; private final SpanMetricReporter spanMetricReporter; + private final Environment environment; - public StreamSpanReporter(HostLocator endpointLocator, SpanMetricReporter spanMetricReporter) { + @Deprecated + public StreamSpanReporter(HostLocator endpointLocator, + SpanMetricReporter spanMetricReporter) { + this(endpointLocator, spanMetricReporter, null); + } + + public StreamSpanReporter(HostLocator endpointLocator, + SpanMetricReporter spanMetricReporter, Environment environment) { this.endpointLocator = endpointLocator; this.spanMetricReporter = spanMetricReporter; + this.environment = environment; } public void setQueue(BlockingQueue queue) { @@ -84,6 +100,9 @@ public class StreamSpanReporter implements SpanReporter { public void report(Span span) { if (span.isExportable()) { try { + if (this.environment != null) { + processLogs(span); + } this.queue.add(span); } catch (Exception e) { this.spanMetricReporter.incrementDroppedSpans(1); @@ -97,4 +116,13 @@ public class StreamSpanReporter implements SpanReporter { } } } + + private void processLogs(Span span) { + for (Log spanLog : span.logs()) { + if (RPC_EVENTS.contains(spanLog.getEvent())) { + span.tag(Span.INSTANCEID, IdUtils.getDefaultInstanceId(this.environment)); + } + } + } + } diff --git a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanReporterTests.java b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanReporterTests.java index 49c5402bf..30deb5f7c 100644 --- a/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanReporterTests.java +++ b/spring-cloud-sleuth-stream/src/test/java/org/springframework/cloud/sleuth/stream/StreamSpanReporterTests.java @@ -16,27 +16,34 @@ package org.springframework.cloud.sleuth.stream; +import java.util.Map; import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.Mockito; import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.mock.env.MockEnvironment; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.then; /** * @author Marcin Grzejszczak */ -@RunWith(MockitoJUnitRunner.class) public class StreamSpanReporterTests { - @Mock HostLocator endpointLocator; - @Mock SpanMetricReporter spanMetricReporter; - @InjectMocks StreamSpanReporter reporter; + HostLocator endpointLocator = Mockito.mock(HostLocator.class); + SpanMetricReporter spanMetricReporter = Mockito.mock(SpanMetricReporter.class); + MockEnvironment mockEnvironment = new MockEnvironment(); + StreamSpanReporter reporter; + + @Before + public void setup() { + this.reporter = new StreamSpanReporter(this.endpointLocator, this.spanMetricReporter, this.mockEnvironment); + } @Test public void should_not_throw_an_exception_when_queue_size_is_exceeded() throws Exception { @@ -46,7 +53,43 @@ public class StreamSpanReporterTests { this.reporter.report(Span.builder().name("bar").exportable(true).build()); - then(spanMetricReporter).should().incrementDroppedSpans(1); + then(this.spanMetricReporter).should().incrementDroppedSpans(1); + } + + @Test + @SuppressWarnings("unchecked") + public void should_append_client_serviceid_when_span_has_rpc_event() throws Exception { + LinkedBlockingQueue queue = new LinkedBlockingQueue<>(1000); + this.reporter.setQueue(queue); + this.mockEnvironment.setProperty("vcap.application.instance_id", "foo"); + Span span = Span.builder().name("bar").exportable(true).build(); + span.logEvent(Span.CLIENT_RECV); + + this.reporter.report(span); + + assertThat(queue).isNotEmpty(); + assertThat(queue.poll()) + .extracting(Span::tags) + .extracting(o -> ((Map) o).get(Span.INSTANCEID)) + .containsExactly("foo"); + } + + @Test + @SuppressWarnings("unchecked") + public void should_not_append_server_serviceid_when_span_has_rpc_event_and_there_is_no_environment() throws Exception { + this.reporter = new StreamSpanReporter(this.endpointLocator, this.spanMetricReporter, null); + LinkedBlockingQueue queue = new LinkedBlockingQueue<>(1000); + this.reporter.setQueue(queue); + Span span = Span.builder().name("bar").exportable(true).build(); + span.logEvent(Span.CLIENT_SEND); + + this.reporter.report(span); + + assertThat(queue).isNotEmpty(); + assertThat(queue.poll()) + .extracting(Span::tags) + .filteredOn(o -> ((Map) o).containsKey(Span.INSTANCEID)) + .isNullOrEmpty(); } } \ No newline at end of file diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java index 0c4594544..829f7aa33 100644 --- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java +++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinAutoConfiguration.java @@ -34,7 +34,7 @@ import org.springframework.cloud.sleuth.sampler.PercentageBasedSampler; import org.springframework.cloud.sleuth.sampler.SamplerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - +import org.springframework.core.env.Environment; /** * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration Auto-configuration} @@ -64,8 +64,9 @@ public class ZipkinAutoConfiguration { } @Bean - public SpanReporter zipkinSpanListener(ZipkinSpanReporter reporter, EndpointLocator endpointLocator) { - return new ZipkinSpanListener(reporter, endpointLocator); + public SpanReporter zipkinSpanListener(ZipkinSpanReporter reporter, EndpointLocator endpointLocator, + Environment environment) { + return new ZipkinSpanListener(reporter, endpointLocator, environment); } @Configuration diff --git a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java index e10ec4936..f00aa22d3 100644 --- a/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java +++ b/spring-cloud-sleuth-zipkin/src/main/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListener.java @@ -21,9 +21,11 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import org.springframework.cloud.commons.util.IdUtils; import org.springframework.cloud.sleuth.Log; import org.springframework.cloud.sleuth.Span; import org.springframework.cloud.sleuth.SpanReporter; +import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; import zipkin.Annotation; @@ -41,13 +43,17 @@ public class ZipkinSpanListener implements SpanReporter { private static final List ZIPKIN_START_EVENTS = Arrays.asList( Constants.CLIENT_RECV, Constants.SERVER_RECV ); + private static final List RPC_EVENTS = Arrays.asList( + Constants.CLIENT_RECV, Constants.CLIENT_SEND, Constants.SERVER_RECV, Constants.SERVER_SEND + ); private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory .getLog(ZipkinSpanListener.class); private static final Charset UTF_8 = Charset.forName("UTF-8"); private static final byte[] UNKNOWN_BYTES = "unknown".getBytes(UTF_8); - private ZipkinSpanReporter reporter; + private final ZipkinSpanReporter reporter; + private final Environment environment; /** * Endpoint is the visible IP address of this service, the port it is listening on and * the service name from discovery. @@ -55,9 +61,16 @@ public class ZipkinSpanListener implements SpanReporter { // Visible for testing EndpointLocator endpointLocator; + @Deprecated public ZipkinSpanListener(ZipkinSpanReporter reporter, EndpointLocator endpointLocator) { + this(reporter, endpointLocator, null); + } + + public ZipkinSpanListener(ZipkinSpanReporter reporter, EndpointLocator endpointLocator, + Environment environment) { this.reporter = reporter; this.endpointLocator = endpointLocator; + this.environment = environment; } /** @@ -76,15 +89,10 @@ public class ZipkinSpanListener implements SpanReporter { zipkin.Span convert(Span span) { zipkin.Span.Builder zipkinSpan = zipkin.Span.builder(); - // A zipkin span without any annotations cannot be queried, add special "lc" to avoid that. - if (notClientOrServer(span)) { - ensureLocalComponent(span, zipkinSpan); - } - addZipkinAnnotations(zipkinSpan, span, this.endpointLocator.local()); - addZipkinBinaryAnnotations(zipkinSpan, span, this.endpointLocator.local()); - if (hasClientSend(span)) { - ensureServerAddr(span, zipkinSpan); - } + Endpoint endpoint = this.endpointLocator.local(); + processLogs(span, zipkinSpan, endpoint); + addZipkinAnnotations(zipkinSpan, span, endpoint); + addZipkinBinaryAnnotations(zipkinSpan, span, endpoint); // In the RPC span model, the client owns the timestamp and duration of the span. If we // were propagated an id, we can assume that we shouldn't report timestamp or duration, // rather let the client do that. Worst case we were propagated an unreported ID and @@ -134,22 +142,40 @@ public class ZipkinSpanListener implements SpanReporter { } } - private boolean notClientOrServer(Span span) { + // Instead of going through the list of logs multiple times we're doing it only once + private void processLogs(Span span, zipkin.Span.Builder zipkinSpan, Endpoint endpoint) { + boolean notClientOrServer = true; + boolean hasClientSend = false; + boolean instanceIdToTag = false; for (Log log : span.logs()) { + if (RPC_EVENTS.contains(log.getEvent())) { + instanceIdToTag = true; + } if (ZIPKIN_START_EVENTS.contains(log.getEvent())) { - return false; + notClientOrServer = false; + } + if (Constants.CLIENT_SEND.equals(log.getEvent())) { + hasClientSend = !span.tags().containsKey(Constants.SERVER_ADDR); } } - return true; + if (notClientOrServer) { + // A zipkin span without any annotations cannot be queried, add special "lc" to avoid that. + ensureLocalComponent(span, zipkinSpan); + } + if (hasClientSend) { + ensureServerAddr(span, zipkinSpan); + } + if (instanceIdToTag && this.environment != null) { + setInstanceIdIfPresent(zipkinSpan, endpoint, Span.INSTANCEID); + } } - private boolean hasClientSend(Span span) { - for (Log log : span.logs()) { - if (Constants.CLIENT_SEND.equals(log.getEvent())) { - return !span.tags().containsKey(Constants.SERVER_ADDR); - } + private void setInstanceIdIfPresent(zipkin.Span.Builder zipkinSpan, + Endpoint endpoint, String key) { + String property = IdUtils.getDefaultInstanceId(this.environment); + if (StringUtils.hasText(property)) { + addZipkinBinaryAnnotation(key, property, endpoint, zipkinSpan); } - return false; } /** @@ -172,15 +198,20 @@ public class ZipkinSpanListener implements SpanReporter { private void addZipkinBinaryAnnotations(zipkin.Span.Builder zipkinSpan, Span span, Endpoint ep) { for (Map.Entry e : span.tags().entrySet()) { - BinaryAnnotation binaryAnn = BinaryAnnotation.builder() - .type(BinaryAnnotation.Type.STRING) - .key(e.getKey()) - .value(e.getValue().getBytes(UTF_8)) - .endpoint(ep).build(); - zipkinSpan.addBinaryAnnotation(binaryAnn); + addZipkinBinaryAnnotation(e.getKey(), e.getValue(), ep, zipkinSpan); } } + private void addZipkinBinaryAnnotation(String key, String value, Endpoint ep, + zipkin.Span.Builder zipkinSpan) { + BinaryAnnotation binaryAnn = BinaryAnnotation.builder() + .type(BinaryAnnotation.Type.STRING) + .key(key) + .value(value.getBytes(UTF_8)) + .endpoint(ep).build(); + zipkinSpan.addBinaryAnnotation(binaryAnn); + } + /** * There could be instrumentation delay between span creation and the * semantic start of the span (client send). When there's a difference, diff --git a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java index c38cc37c5..7cd41d5cf 100644 --- a/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java +++ b/spring-cloud-sleuth-zipkin/src/test/java/org/springframework/cloud/sleuth/zipkin/ZipkinSpanListenerTests.java @@ -34,6 +34,8 @@ import org.springframework.cloud.sleuth.zipkin.ZipkinSpanListenerTests.TestConfi import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.mock.env.MockEnvironment; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import zipkin.Constants; @@ -52,7 +54,10 @@ public class ZipkinSpanListenerTests { @Autowired Tracer tracer; @Autowired ApplicationContext application; @Autowired TestConfiguration test; - @Autowired ZipkinSpanListener spanReporter; + @Autowired ZipkinSpanListener spanListener; + @Autowired ZipkinSpanReporter spanReporter; + @Autowired MockEnvironment mockEnvironment; + @Autowired EndpointLocator endpointLocator; @PostConstruct public void init() { @@ -69,7 +74,7 @@ public class ZipkinSpanListenerTests { span.logEvent("hystrix/retry"); // System.currentTimeMillis span.stop(); - zipkin.Span result = this.spanReporter.convert(span); + zipkin.Span result = this.spanListener.convert(span); assertThat(result.timestamp) .isEqualTo(span.getBegin() * 1000); @@ -90,7 +95,7 @@ public class ZipkinSpanListenerTests { Thread.sleep(20); span.stop(); - zipkin.Span result = this.spanReporter.convert(span); + zipkin.Span result = this.spanListener.convert(span); assertThat(result.timestamp) .isEqualTo(span.getBegin() * 1000); @@ -107,7 +112,7 @@ public class ZipkinSpanListenerTests { @Test public void doesntSetDurationWhenStillRunning() { Span span = Span.builder().traceId(1L).name("http:api").build(); - zipkin.Span result = this.spanReporter.convert(span); + zipkin.Span result = this.spanListener.convert(span); assertThat(result.timestamp) .isGreaterThan(0); // sanity check it did start @@ -124,7 +129,7 @@ public class ZipkinSpanListenerTests { @Test public void doesntSetTimestampOrDurationWhenRemote() { this.parent.stop(); - zipkin.Span result = this.spanReporter.convert(this.parent); + zipkin.Span result = this.spanListener.convert(this.parent); assertThat(result.timestamp) .isNull(); @@ -138,10 +143,10 @@ public class ZipkinSpanListenerTests { this.parent.logEvent("hystrix/retry"); this.parent.tag("spring-boot/version", "1.3.1.RELEASE"); - zipkin.Span result = this.spanReporter.convert(this.parent); + zipkin.Span result = this.spanListener.convert(this.parent); assertThat(result.annotations.get(0).endpoint) - .isEqualTo(this.spanReporter.endpointLocator.local()); + .isEqualTo(this.spanListener.endpointLocator.local()); assertThat(result.binaryAnnotations.get(0).endpoint) .isEqualTo(result.annotations.get(0).endpoint); } @@ -149,7 +154,7 @@ public class ZipkinSpanListenerTests { /** zipkin's Endpoint.serviceName should never be null. */ @Test public void localEndpointIncludesServiceName() { - assertThat(this.spanReporter.endpointLocator.local().serviceName) + assertThat(this.spanListener.endpointLocator.local().serviceName) .isNotEmpty(); } @@ -172,7 +177,7 @@ public class ZipkinSpanListenerTests { Span context = this.tracer.createSpan("http:child", this.parent); context.logEvent(Span.CLIENT_SEND); logServerReceived(this.parent); - logServerSent(this.spanReporter, this.parent); + logServerSent(this.spanListener, this.parent); this.tracer.close(context); assertEquals(2, this.test.zipkinSpans.size()); } @@ -195,7 +200,7 @@ public class ZipkinSpanListenerTests { this.parent.logEvent("hystrix/retry"); this.parent.stop(); - zipkin.Span result = this.spanReporter.convert(this.parent); + zipkin.Span result = this.spanListener.convert(this.parent); assertThat(result.binaryAnnotations) .extracting(input -> input.key) @@ -208,7 +213,7 @@ public class ZipkinSpanListenerTests { this.parent.tag(Span.SPAN_PEER_SERVICE_TAG_NAME, "fooservice"); this.parent.stop(); - zipkin.Span result = this.spanReporter.convert(this.parent); + zipkin.Span result = this.spanListener.convert(this.parent); assertThat(result.binaryAnnotations) .filteredOn("key", Constants.SERVER_ADDR) @@ -220,7 +225,7 @@ public class ZipkinSpanListenerTests { this.parent.logEvent(Constants.CLIENT_SEND); this.parent.stop(); - zipkin.Span result = this.spanReporter.convert(this.parent); + zipkin.Span result = this.spanListener.convert(this.parent); assertThat(result.binaryAnnotations) .filteredOn("key", Constants.SERVER_ADDR) @@ -231,7 +236,7 @@ public class ZipkinSpanListenerTests { public void converts128BitTraceId() { Span span = Span.builder().traceIdHigh(1L).traceId(2L).spanId(3L).name("foo").build(); - zipkin.Span result = this.spanReporter.convert(span); + zipkin.Span result = this.spanListener.convert(span); assertThat(result.traceIdHigh).isEqualTo(span.getTraceIdHigh()); assertThat(result.traceId).isEqualTo(span.getTraceId()); @@ -243,7 +248,7 @@ public class ZipkinSpanListenerTests { this.parent.tag(Span.SPAN_PEER_SERVICE_TAG_NAME, "fooservice"); this.parent.stop(); - zipkin.Span result = this.spanReporter.convert(this.parent); + zipkin.Span result = this.spanListener.convert(this.parent); assertThat(result.binaryAnnotations) .filteredOn("key", Constants.SERVER_ADDR) @@ -255,11 +260,38 @@ public class ZipkinSpanListenerTests { public void shouldNotReportToZipkinWhenSpanIsNotExportable() { Span span = Span.builder().exportable(false).build(); - this.spanReporter.report(span); + this.spanListener.report(span); assertThat(this.test.zipkinSpans).isEmpty(); } + @Test + public void shouldAddClientServiceIdTagWhenSpanContainsRpcEvent() { + this.parent.logEvent(Span.CLIENT_SEND); + this.mockEnvironment.setProperty("vcap.application.instance_id", "foo"); + + zipkin.Span result = this.spanListener.convert(this.parent); + + assertThat(result.binaryAnnotations) + .filteredOn("key", Span.INSTANCEID) + .extracting(input -> input.value) + .containsOnly("foo".getBytes()); + } + + @Test + public void shouldNotAddAnyServiceIdTagWhenSpanContainsRpcEventAndThereIsNoEnvironment() { + this.parent.logEvent(Span.CLIENT_RECV); + ZipkinSpanListener spanListener = new ZipkinSpanListener(this.spanReporter, + this.endpointLocator, null); + + zipkin.Span result = spanListener.convert(this.parent); + + assertThat(result.binaryAnnotations) + .filteredOn("key", Span.INSTANCEID) + .extracting(input -> input.value) + .isEmpty(); + } + @Configuration @EnableAutoConfiguration protected static class TestConfiguration { @@ -276,6 +308,10 @@ public class ZipkinSpanListenerTests { return this.zipkinSpans::add; } + @Bean @Primary MockEnvironment mockEnvironment() { + return new MockEnvironment(); + } + } }