diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java index 865303f13..3a9482962 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/Trace.java @@ -53,9 +53,8 @@ public interface Trace { String SPAN_ID_NAME = "X-Span-Id"; String TRACE_ID_NAME = "X-Trace-Id"; - String SPAN_NAME_NAME = "X-Span-Name"; String PARENT_ID_NAME = "X-Parent-Id"; - String PROCESS_ID_NAME = "X-Process-Id"; + String NOT_SAMPLED_NAME = "X-Not-Sampled"; /** * Creates a trace scope wrapping a new span. diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java index c34cf3613..3a07c331e 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/SpanMessageHeaders.java @@ -16,10 +16,9 @@ package org.springframework.cloud.sleuth.instrument.integration; +import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME; import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; import java.util.HashMap; @@ -37,27 +36,28 @@ import org.springframework.messaging.Message; public class SpanMessageHeaders { public static Message addSpanHeaders(Message message, Span span) { - if (span==null) { + if (span == null) { + if (!message.getHeaders().containsKey(NOT_SAMPLED_NAME)) { + return MessageBuilder.fromMessage(message).setHeader(NOT_SAMPLED_NAME, "") + .build(); + } return message; } Map headers = new HashMap(); addHeader(headers, TRACE_ID_NAME, span.getTraceId()); addHeader(headers, SPAN_ID_NAME, span.getSpanId()); addHeader(headers, PARENT_ID_NAME, getFirst(span.getParents())); - addHeader(headers, SPAN_NAME_NAME, span.getName()); - addHeader(headers, PROCESS_ID_NAME, span.getProcessId()); return MessageBuilder.fromMessage(message).copyHeaders(headers).build(); } private static void addHeader(Map headers, String name, String value) { - if (value!=null) { + if (value != null) { headers.put(name, value); } } private static String getFirst(List parents) { - return parents==null || parents.isEmpty() ? null : parents.get(0); + return parents == null || parents.isEmpty() ? null : parents.get(0); } - } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java index 735c631af..0d23ff943 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptor.java @@ -16,10 +16,9 @@ package org.springframework.cloud.sleuth.instrument.integration; +import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME; import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; import static org.springframework.util.StringUtils.hasText; @@ -47,7 +46,7 @@ public class TraceChannelInterceptor extends ChannelInterceptorAdapter { @Override public Message preSend(Message message, MessageChannel channel) { - if (TraceContextHolder.isTracing()) { + if (TraceContextHolder.isTracing() || message.getHeaders().containsKey(NOT_SAMPLED_NAME)) { return SpanMessageHeaders.addSpanHeaders(message, TraceContextHolder.getCurrentSpan()); } String spanId = getHeader(message, SPAN_ID_NAME); @@ -60,14 +59,6 @@ public class TraceChannelInterceptor extends ChannelInterceptorAdapter { MilliSpanBuilder span = MilliSpan.builder().traceId(traceId).spanId(spanId); String parentId = getHeader(message, PARENT_ID_NAME); - String processId = getHeader(message, PROCESS_ID_NAME); - String spanName = getHeader(message, SPAN_NAME_NAME); - if (spanName != null) { - span.name(spanName); - } - if (processId != null) { - span.processId(processId); - } if (parentId != null) { span.parent(parentId); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java index 3cc2ebf02..a7d344883 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/integration/TraceContextPropagationChannelInterceptor.java @@ -17,9 +17,7 @@ package org.springframework.cloud.sleuth.instrument.integration; import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; import static org.springframework.cloud.sleuth.TraceContextHolder.getCurrentSpan; import static org.springframework.cloud.sleuth.TraceContextHolder.setCurrentSpan; @@ -144,15 +142,10 @@ implements ExecutorChannelInterceptor { setHeader(headers, SPAN_ID_NAME, this.span.getSpanId()); setHeader(headers, TRACE_ID_NAME, this.span.getTraceId()); - setHeader(headers, SPAN_NAME_NAME, this.span.getName()); String parentId = getParentId(getCurrentSpan()); if (parentId != null) { setHeader(headers, PARENT_ID_NAME, parentId); } - String processId = this.span.getProcessId(); - if (processId != null) { - setHeader(headers, PROCESS_ID_NAME, processId); - } this.messageHeaders = new MessageHeaders(headers); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java index d208a8094..a16eba717 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java @@ -15,10 +15,9 @@ */ package org.springframework.cloud.sleuth.instrument.web; +import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME; import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; import static org.springframework.util.StringUtils.hasText; @@ -82,13 +81,15 @@ public class TraceFilter extends OncePerRequestFilter { throws ServletException, IOException { String uri = this.urlPathHelper.getPathWithinApplication(request); - boolean skip = this.skipPattern.matcher(uri).matches(); + boolean skip = this.skipPattern.matcher(uri).matches() || getHeader(request, response, NOT_SAMPLED_NAME)!=null; TraceScope traceScope = (TraceScope) request.getAttribute(TRACE_REQUEST_ATTR); if (traceScope != null) { this.trace.continueSpan(traceScope.getSpan()); } - else if (!skip) { + else if (skip) { + addToResponseIfNotPresent(response, NOT_SAMPLED_NAME, ""); + } else { String spanId = getHeader(request, response, SPAN_ID_NAME); String traceId = getHeader(request, response, TRACE_ID_NAME); String name = "http" + uri; @@ -97,14 +98,6 @@ public class TraceFilter extends OncePerRequestFilter { MilliSpanBuilder span = MilliSpan.builder().traceId(traceId) .spanId(spanId); String parentId = getHeader(request, response, PARENT_ID_NAME); - String processId = getHeader(request, response, PROCESS_ID_NAME); - String parentName = getHeader(request, response, SPAN_NAME_NAME); - if (parentName != null) { - span.name(parentName); - } - if (processId != null) { - span.processId(processId); - } if (parentId != null) { span.parent(parentId); } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java index 3f1f2e301..7b149688b 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptor.java @@ -16,9 +16,7 @@ package org.springframework.cloud.sleuth.instrument.web.client; import static org.springframework.cloud.sleuth.Trace.PARENT_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.PROCESS_ID_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; -import static org.springframework.cloud.sleuth.Trace.SPAN_NAME_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; import static org.springframework.cloud.sleuth.TraceContextHolder.getCurrentSpan; import static org.springframework.cloud.sleuth.TraceContextHolder.isTracing; @@ -65,9 +63,7 @@ ApplicationEventPublisherAware { } setHeader(request, SPAN_ID_NAME, getCurrentSpan().getSpanId()); setHeader(request, TRACE_ID_NAME, getCurrentSpan().getTraceId()); - setHeader(request, SPAN_NAME_NAME, getCurrentSpan().getName()); setHeader(request, PARENT_ID_NAME, getParentId(getCurrentSpan())); - setHeader(request, PROCESS_ID_NAME, getCurrentSpan().getProcessId()); publish(new ClientSentEvent(this, getCurrentSpan())); return new TraceHttpResponse(this, execution.execute(request, body)); } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java index 6cec6b3bc..aa1bab808 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/integration/TraceChannelInterceptorTests.java @@ -17,6 +17,8 @@ package org.springframework.cloud.sleuth.instrument.integration; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.springframework.cloud.sleuth.Trace.NOT_SAMPLED_NAME; import static org.springframework.cloud.sleuth.Trace.SPAN_ID_NAME; import static org.springframework.cloud.sleuth.Trace.TRACE_ID_NAME; @@ -48,7 +50,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; * @author Dave Syer */ @RunWith(SpringJUnit4ClassRunner.class) -@SpringApplicationConfiguration(classes=App.class) +@SpringApplicationConfiguration(classes = App.class) @IntegrationTest @DirtiesContext public class TraceChannelInterceptorTests implements MessageHandler { @@ -78,6 +80,16 @@ public class TraceChannelInterceptorTests implements MessageHandler { this.channel.unsubscribe(this); } + @Test + public void testNoSpanCreation() { + this.channel.send(MessageBuilder.withPayload("hi").setHeader(NOT_SAMPLED_NAME, "") + .build()); + assertNotNull("message was null", this.message); + + String spanId = this.message.getHeaders().get(SPAN_ID_NAME, String.class); + assertNull("spanId was not null", spanId); + } + @Test public void testSpanCreation() { this.channel.send(MessageBuilder.withPayload("hi").build()); @@ -92,7 +104,8 @@ public class TraceChannelInterceptorTests implements MessageHandler { @Test public void testHeaderCreation() { - TraceScope traceScope = this.trace.startSpan("testSendMessage", new AlwaysSampler(), null); + TraceScope traceScope = this.trace.startSpan("testSendMessage", + new AlwaysSampler(), null); this.channel.send(MessageBuilder.withPayload("hi").build()); traceScope.close(); assertNotNull("message was null", this.message); diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java index 4edf41091..290594456 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceRestTemplateInterceptorTests.java @@ -88,7 +88,7 @@ public class TraceRestTemplateInterceptorTests { public Map home(@RequestHeader HttpHeaders headers) { Map map = new HashMap(); addHeaders(map, headers, Trace.SPAN_ID_NAME, Trace.TRACE_ID_NAME, - Trace.PARENT_ID_NAME, Trace.SPAN_NAME_NAME, Trace.PROCESS_ID_NAME); + Trace.PARENT_ID_NAME); return map; } 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 6653d0c1b..5d451e8d6 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 @@ -37,6 +37,7 @@ import org.springframework.cloud.sleuth.event.SpanStartedEvent; import org.springframework.cloud.sleuth.event.SpanStoppedEvent; import org.springframework.context.event.EventListener; import org.springframework.core.annotation.Order; +import org.springframework.util.StringUtils; import com.github.kristofa.brave.SpanCollector; import com.twitter.zipkin.gen.Annotation; @@ -64,7 +65,7 @@ public class ZipkinSpanListener { @EventListener @Order(0) public void start(SpanStartedEvent event) { - if (event.getParent()!=null && event.getParent().isRemote()) { + if (event.getParent() != null && event.getParent().isRemote()) { event.getParent().addTimelineAnnotation(zipkinCoreConstants.SERVER_RECV); } event.getSpan().addTimelineAnnotation("start"); @@ -85,7 +86,7 @@ public class ZipkinSpanListener { @EventListener @Order(0) public void stop(SpanStoppedEvent event) { - if (event.getParent()!=null && event.getParent().isRemote()) { + if (event.getParent() != null && event.getParent().isRemote()) { event.getParent().addTimelineAnnotation(zipkinCoreConstants.SERVER_SEND); this.spanCollector.collect(convert(event.getParent())); } @@ -110,17 +111,20 @@ public class ZipkinSpanListener { Endpoint ep = new Endpoint(address, port.shortValue(), serviceName); List annotationList = createZipkinAnnotations(span, ep); - List binaryAnnotationList = createZipkinBinaryAnnotations(span, ep); + List binaryAnnotationList = createZipkinBinaryAnnotations(span, + ep); zipkinSpan.setTrace_id(hash(span.getTraceId())); if (span.getParents().size() > 0) { if (span.getParents().size() > 1) { - log.error("zipkin doesn't support spans with multiple parents. Omitting " + - "other parents for " + span); + log.error("zipkin doesn't support spans with multiple parents. Omitting " + + "other parents for " + span); } zipkinSpan.setParent_id(hash(span.getParents().get(0))); } zipkinSpan.setId(hash(span.getSpanId())); - zipkinSpan.setName(span.getName()); + if (StringUtils.hasText(span.getName())) { + zipkinSpan.setName(span.getName()); + } zipkinSpan.setAnnotations(annotationList); zipkinSpan.setBinary_annotations(binaryAnnotationList); return zipkinSpan; @@ -130,8 +134,9 @@ public class ZipkinSpanListener { Integer port; if (this.serverProperties.getPort() != null) { port = this.serverProperties.getPort(); - } else { - port = 8080; //TODO: support random port + } + else { + port = 8080; // TODO: support random port } return port; } @@ -140,8 +145,9 @@ public class ZipkinSpanListener { String address; if (this.serverProperties.getAddress() != null) { address = this.serverProperties.getAddress().getHostAddress(); - } else { - address = "127.0.0.1"; //TODO: get address from config + } + else { + address = "127.0.0.1"; // TODO: get address from config } return ipAddressToInt(address); } @@ -150,18 +156,19 @@ public class ZipkinSpanListener { String serviceName; if (span.getProcessId() != null) { serviceName = span.getProcessId().toLowerCase(); - } else { + } + else { serviceName = this.appName; } return serviceName; } - private int ipAddressToInt(final String ip) { InetAddress inetAddress = null; try { inetAddress = InetAddress.getByName(ip); - } catch (final UnknownHostException e) { + } + catch (final UnknownHostException e) { throw new IllegalArgumentException(e); } return ByteBuffer.wrap(inetAddress.getAddress()).getInt(); @@ -170,25 +177,27 @@ public class ZipkinSpanListener { /** * Add annotations from the sleuth Span. */ - private List createZipkinAnnotations(Span span, - Endpoint endpoint) { + private List createZipkinAnnotations(Span span, Endpoint endpoint) { List annotationList = new ArrayList<>(); long srTime = 0, csTime = 0; // add sleuth time annotation for (TimelineAnnotation ta : span.getTimelineAnnotations()) { - Annotation zipkinAnnotation = createZipkinAnnotation(ta.getMsg(), ta.getTime(), 0, endpoint, true); + Annotation zipkinAnnotation = createZipkinAnnotation(ta.getMsg(), + ta.getTime(), 0, endpoint, true); if (zipkinCoreConstants.SERVER_RECV.equals(ta.getMsg())) { srTime = ta.getTime(); } - if (zipkinCoreConstants.SERVER_SEND.equals(ta.getMsg()) && srTime!=0) { - zipkinAnnotation.setDuration(new Long(ta.getTime() - srTime).intValue()*1000); + if (zipkinCoreConstants.SERVER_SEND.equals(ta.getMsg()) && srTime != 0) { + zipkinAnnotation + .setDuration(new Long(ta.getTime() - srTime).intValue() * 1000); } if (zipkinCoreConstants.CLIENT_SEND.equals(ta.getMsg())) { csTime = ta.getTime(); } - if (zipkinCoreConstants.CLIENT_RECV.equals(ta.getMsg()) && csTime!=0) { - zipkinAnnotation.setDuration(new Long(ta.getTime() - csTime).intValue()*1000); + if (zipkinCoreConstants.CLIENT_RECV.equals(ta.getMsg()) && csTime != 0) { + zipkinAnnotation + .setDuration(new Long(ta.getTime() - csTime).intValue() * 1000); } annotationList.add(zipkinAnnotation); } @@ -209,7 +218,8 @@ public class ZipkinSpanListener { binaryAnn.setKey(e.getKey()); try { binaryAnn.setValue(e.getValue().getBytes("UTF-8")); - } catch (UnsupportedEncodingException ex) { + } + catch (UnsupportedEncodingException ex) { log.error("Error encoding string as UTF-8", ex); } binaryAnn.setHost(endpoint); @@ -221,20 +231,21 @@ public class ZipkinSpanListener { /** * Create an annotation with the correct times and endpoint. * - * @param value Annotation value - * @param time timestamp will be extracted - * @param endpoint the endpoint this annotation will be associated with. + * @param value Annotation value + * @param time timestamp will be extracted + * @param endpoint the endpoint this annotation will be associated with. * @param sendRequest use the first or last timestamp. */ - private static Annotation createZipkinAnnotation(String value, long time, int duration, - Endpoint endpoint, boolean sendRequest) { + private static Annotation createZipkinAnnotation(String value, long time, + int duration, Endpoint endpoint, boolean sendRequest) { Annotation annotation = new Annotation(); annotation.setHost(endpoint); // Zipkin is in microseconds if (sendRequest) { annotation.setTimestamp(time * 1000); - } else { + } + else { annotation.setTimestamp(time * 1000); }