diff --git a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc index 0fb31d3f6..fc72ba0c0 100644 --- a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc +++ b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc @@ -446,6 +446,26 @@ By default Sleuth assumes that when you send a span to Zipkin, you want the span spring.zipkin.service.name: foo ---- +=== Customization of reported spans + +Before reporting spans to e.g. Zipkin you can be interested in modifying that span in some way. + You can achieve that by using the `SpanAdjuster` interface. + +Example of usage: + +In Sleuth we're generating spans with a fixed name. Some users want to modify the name depending on values +of tags. Implementation of the `SpanAdjuster` interface can be used to alter that name. Example: + +[source,yaml] +---- +@Bean +SpanAdjuster customSpanAdjuster() { + return span -> span.toBuilder().name(scrub(span.getName())).build(); +} +---- + +This will lead in changing the name of the reported span just before it gets sent to Zipkin. + === Host locator In order to define the host that is corresponding to a particular span we need to resolve the host name diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NoOpSpanAdjuster.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NoOpSpanAdjuster.java new file mode 100644 index 000000000..52f9bf454 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/NoOpSpanAdjuster.java @@ -0,0 +1,29 @@ +/* + * Copyright 2013-2016 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 org.springframework.cloud.sleuth; + +/** + * Span adjuster that does nothing. + * + * @author Marcin Grzejszczak + * @since 1.1.4 + */ +public class NoOpSpanAdjuster implements SpanAdjuster { + @Override public Span adjust(Span span) { + return span; + } +} 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 fc343ccc4..f8146c946 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 @@ -534,6 +534,13 @@ public class Span implements SpanContext { return new String(result); } + /** + * Converts the span to a {@link SpanBuilder} format + */ + public SpanBuilder toBuilder() { + return builder().from(this); + } + /** * Represents given long id as 16-character lower-hex string * @@ -697,6 +704,7 @@ public class Span implements SpanContext { } public Span.SpanBuilder parents(Collection parents) { + this.parents.clear(); this.parents.addAll(parents); return this; } @@ -707,6 +715,7 @@ public class Span implements SpanContext { } public Span.SpanBuilder logs(Collection logs) { + this.logs.clear(); this.logs.addAll(logs); return this; } @@ -717,6 +726,7 @@ public class Span implements SpanContext { } public Span.SpanBuilder tags(Map tags) { + this.tags.clear(); this.tags.putAll(tags); return this; } @@ -756,6 +766,14 @@ public class Span implements SpanContext { return this; } + public Span.SpanBuilder from(Span span) { + return begin(span.begin).end(span.end).name(span.name) + .traceIdHigh(span.traceIdHigh).traceId(span.traceId) + .parents(span.getParents()).logs(span.logs).tags(span.tags) + .spanId(span.spanId).remote(span.remote).exportable(span.exportable) + .processId(span.processId).savedSpan(span.savedSpan); + } + public Span build() { return new Span(this); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanAdjuster.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanAdjuster.java new file mode 100644 index 000000000..e9d938215 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/SpanAdjuster.java @@ -0,0 +1,37 @@ +/* + * Copyright 2013-2016 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 org.springframework.cloud.sleuth; + +/** + * Adds ability to adjust a span before reporting it. + * + * @author Marcin Grzejszczak + * @since 1.1.4 + */ +public interface SpanAdjuster { + /** + * You can adjust the {@link Span} by creating a new one using the {@link Span.SpanBuilder} + * before reporting it. + * + * In Sleuth we're generating spans with a fixed name. Some users want to modify the name + * depending on some values of tags. Implementation of this interface can be used to alter + * then name. Example: + * + * {@code span -> span.toBuilder().name(scrub(span.getName())).build();} + */ + Span adjust(Span span); +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java index dffdfd63b..57d6d85de 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfiguration.java @@ -23,8 +23,10 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.sleuth.DefaultSpanNamer; +import org.springframework.cloud.sleuth.NoOpSpanAdjuster; import org.springframework.cloud.sleuth.NoOpSpanReporter; import org.springframework.cloud.sleuth.Sampler; +import org.springframework.cloud.sleuth.SpanAdjuster; import org.springframework.cloud.sleuth.SpanNamer; import org.springframework.cloud.sleuth.SpanReporter; import org.springframework.cloud.sleuth.TraceKeys; @@ -83,4 +85,10 @@ public class TraceAutoConfiguration { return new NoOpSpanReporter(); } + @Bean + @ConditionalOnMissingBean + public SpanAdjuster defaultSpanAdjuster() { + return new NoOpSpanAdjuster(); + } + } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/NoOpSpanAdjusterTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/NoOpSpanAdjusterTests.java new file mode 100644 index 000000000..e02985458 --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/NoOpSpanAdjusterTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013-2016 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 org.springframework.cloud.sleuth; + +import org.junit.Test; + +import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then; + +/** + * @author Marcin Grzejszczak + */ +public class NoOpSpanAdjusterTests { + @Test + public void should_return_same_span() { + Span span = Span.builder().spanId(1).build(); + + then(new NoOpSpanAdjuster().adjust(span)).isSameAs(span); + } +} \ No newline at end of file diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/SpanTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/SpanTests.java index c66e4d941..99cef25c8 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/SpanTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/SpanTests.java @@ -253,4 +253,29 @@ public class SpanTests { // We round so that we don't confuse "not started" with a short span. assertThat(span.getAccumulatedMicros()).isEqualTo(1L); } + + @Test + public void should_build_a_span_from_provided_span() throws IOException { + Span span = builder().build(); + + Span builtSpan = Span.builder().from(span).build(); + + assertThat(builtSpan).isEqualTo(span); + } + + @Test + public void should_convert_a_span_to_builder() throws IOException { + Span.SpanBuilder spanBuilder = builder(); + Span span = spanBuilder.build(); + + Span span2 = span.toBuilder().build(); + + assertThat(span).isEqualTo(span2); + } + + private Span.SpanBuilder builder() { + return Span.builder().name("http:name").traceId(1L).spanId(2L).parent(3L) + .begin(1L).end(2L).traceId(3L).exportable(true).parent(4L) + .remote(true).tag("tag", "tag").log(new Log(System.currentTimeMillis(), "log")); + } } 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 84935dedc..50fec4143 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 @@ -28,6 +28,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.sleuth.Sampler; +import org.springframework.cloud.sleuth.SpanAdjuster; import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; import org.springframework.cloud.sleuth.metric.SpanMetricReporter; import org.springframework.cloud.sleuth.metric.TraceMetricsAutoConfiguration; @@ -57,9 +58,9 @@ import org.springframework.scheduling.support.PeriodicTrigger; * @since 1.0.0 */ @Configuration -@EnableConfigurationProperties({SleuthStreamProperties.class, SamplerProperties.class, ZipkinProperties.class}) +@EnableConfigurationProperties({ SleuthStreamProperties.class, SamplerProperties.class, ZipkinProperties.class }) @AutoConfigureAfter(TraceMetricsAutoConfiguration.class) -@AutoConfigureBefore({ChannelBindingAutoConfiguration.class, TraceAutoConfiguration.class, ChannelsEndpointAutoConfiguration.class}) +@AutoConfigureBefore({ ChannelBindingAutoConfiguration.class, TraceAutoConfiguration.class, ChannelsEndpointAutoConfiguration.class }) @EnableBinding(SleuthSource.class) @ConditionalOnProperty(value = "spring.sleuth.stream.enabled", matchIfMissing = true) public class SleuthStreamAutoConfiguration { @@ -79,8 +80,8 @@ public class SleuthStreamAutoConfiguration { @Bean @ConditionalOnMissingBean public StreamSpanReporter sleuthStreamSpanReporter(HostLocator endpointLocator, - SpanMetricReporter spanMetricReporter, Environment environment) { - return new StreamSpanReporter(endpointLocator, spanMetricReporter, environment); + SpanMetricReporter spanMetricReporter, Environment environment, SpanAdjuster spanAdjuster) { + return new StreamSpanReporter(endpointLocator, spanMetricReporter, environment, spanAdjuster); } @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 49cb847f8..90303b45d 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 @@ -27,7 +27,9 @@ import java.util.concurrent.LinkedBlockingQueue; import org.apache.commons.logging.LogFactory; import org.springframework.cloud.commons.util.IdUtils; import org.springframework.cloud.sleuth.Log; +import org.springframework.cloud.sleuth.NoOpSpanAdjuster; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanAdjuster; import org.springframework.cloud.sleuth.SpanReporter; import org.springframework.cloud.sleuth.metric.SpanMetricReporter; import org.springframework.core.env.Environment; @@ -61,6 +63,7 @@ public class StreamSpanReporter implements SpanReporter { private final HostLocator endpointLocator; private final SpanMetricReporter spanMetricReporter; private final Environment environment; + private final SpanAdjuster spanAdjuster; @Deprecated public StreamSpanReporter(HostLocator endpointLocator, @@ -68,11 +71,18 @@ public class StreamSpanReporter implements SpanReporter { this(endpointLocator, spanMetricReporter, null); } + @Deprecated public StreamSpanReporter(HostLocator endpointLocator, SpanMetricReporter spanMetricReporter, Environment environment) { + this(endpointLocator, spanMetricReporter, environment, new NoOpSpanAdjuster()); + } + + public StreamSpanReporter(HostLocator endpointLocator, + SpanMetricReporter spanMetricReporter, Environment environment, SpanAdjuster spanAdjuster) { this.endpointLocator = endpointLocator; this.spanMetricReporter = spanMetricReporter; this.environment = environment; + this.spanAdjuster = spanAdjuster; } public void setQueue(BlockingQueue queue) { @@ -101,21 +111,23 @@ public class StreamSpanReporter implements SpanReporter { @Override public void report(Span span) { - if (span.isExportable()) { + Span spanToReport = span; + if (spanToReport.isExportable()) { try { if (this.environment != null) { - processLogs(span); + processLogs(spanToReport); } - this.queue.add(span); + spanToReport = this.spanAdjuster.adjust(spanToReport); + this.queue.add(spanToReport); } catch (Exception e) { this.spanMetricReporter.incrementDroppedSpans(1); if (log.isDebugEnabled()) { - log.debug("The span " + span + " will not be sent to Zipkin due to [" + e + "]"); + log.debug("The span " + spanToReport + " will not be sent to Zipkin due to [" + e + "]"); } } } else { if (log.isDebugEnabled()) { - log.debug("The span " + span + " will not be sent to Zipkin due to sampling"); + log.debug("The span " + spanToReport + " will not be sent to Zipkin due to sampling"); } } } 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 d0fc126d1..032362a81 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 @@ -92,4 +92,23 @@ public class StreamSpanReporterTests { .isNullOrEmpty(); } + @Test + @SuppressWarnings("unchecked") + public void should_adjust_span_before_reporting_it() throws Exception { + this.reporter = new StreamSpanReporter(this.endpointLocator, this.spanMetricReporter, null, + span -> Span.builder().from(span).name("foo").build()); + 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::getName) + .filteredOn(o -> o.equals("foo")) + .isNotEmpty(); + } + } \ 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 2aca6ad03..796180dcd 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 @@ -27,6 +27,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.commons.util.InetUtils; import org.springframework.cloud.sleuth.Sampler; +import org.springframework.cloud.sleuth.SpanAdjuster; import org.springframework.cloud.sleuth.SpanReporter; import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; import org.springframework.cloud.sleuth.metric.SpanMetricReporter; @@ -83,8 +84,8 @@ public class ZipkinAutoConfiguration { @Bean public SpanReporter zipkinSpanListener(ZipkinSpanReporter reporter, EndpointLocator endpointLocator, - Environment environment) { - return new ZipkinSpanListener(reporter, endpointLocator, environment); + Environment environment, SpanAdjuster spanAdjuster) { + return new ZipkinSpanListener(reporter, endpointLocator, environment, spanAdjuster); } @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 f7fadf243..422f8f8c4 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 @@ -23,7 +23,9 @@ import java.util.Map; import org.springframework.cloud.commons.util.IdUtils; import org.springframework.cloud.sleuth.Log; +import org.springframework.cloud.sleuth.NoOpSpanAdjuster; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanAdjuster; import org.springframework.cloud.sleuth.SpanReporter; import org.springframework.core.env.Environment; import org.springframework.util.StringUtils; @@ -54,6 +56,7 @@ public class ZipkinSpanListener implements SpanReporter { private final ZipkinSpanReporter reporter; private final Environment environment; + private final SpanAdjuster spanAdjuster; /** * Endpoint is the visible IP address of this service, the port it is listening on and * the service name from discovery. @@ -66,11 +69,18 @@ public class ZipkinSpanListener implements SpanReporter { this(reporter, endpointLocator, null); } + @Deprecated public ZipkinSpanListener(ZipkinSpanReporter reporter, EndpointLocator endpointLocator, Environment environment) { + this(reporter, endpointLocator, environment, new NoOpSpanAdjuster()); + } + + public ZipkinSpanListener(ZipkinSpanReporter reporter, EndpointLocator endpointLocator, + Environment environment, SpanAdjuster spanAdjuster) { this.reporter = reporter; this.endpointLocator = endpointLocator; this.environment = environment; + this.spanAdjuster = spanAdjuster; } /** @@ -88,34 +98,34 @@ public class ZipkinSpanListener implements SpanReporter { // Visible for testing zipkin.Span convert(Span span) { //TODO: Consider adding support for the debug flag (related to #496) + Span convertedSpan = this.spanAdjuster.adjust(span); zipkin.Span.Builder zipkinSpan = zipkin.Span.builder(); - Endpoint endpoint = this.endpointLocator.local(); - processLogs(span, zipkinSpan, endpoint); - addZipkinAnnotations(zipkinSpan, span, endpoint); - addZipkinBinaryAnnotations(zipkinSpan, span, endpoint); + processLogs(convertedSpan, zipkinSpan, endpoint); + addZipkinAnnotations(zipkinSpan, convertedSpan, endpoint); + addZipkinBinaryAnnotations(zipkinSpan, convertedSpan, 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 // Zipkin backfills timestamp and duration. - if (!span.isRemote()) { - zipkinSpan.timestamp(span.getBegin() * 1000L); - if (!span.isRunning()) { // duration is authoritative, only write when the span stopped - zipkinSpan.duration(calculateDurationInMicros(span)); + if (!convertedSpan.isRemote()) { + zipkinSpan.timestamp(convertedSpan.getBegin() * 1000L); + if (!convertedSpan.isRunning()) { // duration is authoritative, only write when the span stopped + zipkinSpan.duration(calculateDurationInMicros(convertedSpan)); } } - zipkinSpan.traceIdHigh(span.getTraceIdHigh()); - zipkinSpan.traceId(span.getTraceId()); - if (span.getParents().size() > 0) { - if (span.getParents().size() > 1) { + zipkinSpan.traceIdHigh(convertedSpan.getTraceIdHigh()); + zipkinSpan.traceId(convertedSpan.getTraceId()); + if (convertedSpan.getParents().size() > 0) { + if (convertedSpan.getParents().size() > 1) { log.error("Zipkin doesn't support spans with multiple parents. Omitting " - + "other parents for " + span); + + "other parents for " + convertedSpan); } - zipkinSpan.parentId(span.getParents().get(0)); + zipkinSpan.parentId(convertedSpan.getParents().get(0)); } - zipkinSpan.id(span.getSpanId()); - if (StringUtils.hasText(span.getName())) { - zipkinSpan.name(span.getName()); + zipkinSpan.id(convertedSpan.getSpanId()); + if (StringUtils.hasText(convertedSpan.getName())) { + zipkinSpan.name(convertedSpan.getName()); } return zipkinSpan.build(); } 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 fa244367f..59ae127b8 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 @@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.sleuth.Sampler; import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.SpanAdjuster; import org.springframework.cloud.sleuth.SpanReporter; import org.springframework.cloud.sleuth.Tracer; import org.springframework.cloud.sleuth.sampler.AlwaysSampler; @@ -292,6 +293,19 @@ public class ZipkinSpanListenerTests { .isEmpty(); } + @Test + public void should_adjust_span_before_reporting_it() { + this.parent.logEvent(Span.CLIENT_RECV); + ZipkinSpanListener spanListener = new ZipkinSpanListener(this.spanReporter, + this.endpointLocator, null, span -> Span.builder().from(span) + .name("foo") + .build()); + + zipkin.Span result = spanListener.convert(this.parent); + + assertThat(result.name).isEqualTo("foo"); + } + @Configuration @EnableAutoConfiguration protected static class TestConfiguration {