private static boolean hasClientSend(Span span) { for (org.springframework.cloud.sleuth.Log log : span.logs()) { if (Constants.CLIENT_SEND.equals(log.getEvent())) { return !span.tags().containsKey(Constants.SERVER_ADDR); } } return false; }
public static Message<?> addSpanHeaders(TraceKeys traceKeys, Message<?> message, Span span) { if (span == null) { if (!message.getHeaders().containsKey(Span.NOT_SAMPLED_NAME)) { return MessageBuilder.fromMessage(message).setHeader(Span.NOT_SAMPLED_NAME, "").build(); } return message; } Map<String, String> headers = new HashMap<>(); addHeader(headers, Span.TRACE_ID_NAME, Span.toHex(span.getTraceId())); addHeader(headers, Span.SPAN_ID_NAME, Span.toHex(span.getSpanId())); if (span.isExportable()) { addAnnotations(traceKeys, message, span); Long parentId = getFirst(span.getParents()); if (parentId != null) { addHeader(headers, Span.PARENT_ID_NAME, Span.toHex(parentId)); } addHeader(headers, Span.SPAN_NAME_NAME, span.getName()); addHeader(headers, Span.PROCESS_ID_NAME, span.getProcessId()); } else { addHeader(headers, Span.NOT_SAMPLED_NAME, ""); } return MessageBuilder.fromMessage(message).copyHeaders(headers).build(); }
// VisibleForTesting static zipkin.Span convert(Span span, Host host) { Builder zipkinSpan = zipkin.Span.builder(); Endpoint ep = Endpoint.create(host.getServiceName(), host.getIpv4(), host.getPort().shortValue()); // A zipkin span without any annotations cannot be queried, add special "lc" to // avoid that. if (notClientOrServer(span)) { ensureLocalComponent(span, zipkinSpan, ep); } ZipkinMessageListener.addZipkinAnnotations(zipkinSpan, span, ep); ZipkinMessageListener.addZipkinBinaryAnnotations(zipkinSpan, span, ep); if (hasClientSend(span)) { ensureServerAddr(span, zipkinSpan, ep); } zipkinSpan.timestamp(span.getBegin() * 1000); zipkinSpan.duration(span.getAccumulatedMillis() * 1000); zipkinSpan.traceId(span.getTraceId()); if (span.getParents().size() > 0) { if (span.getParents().size() > 1) { log.debug( "zipkin doesn't support spans with multiple parents. Omitting " + "other parents for " + span); } zipkinSpan.parentId(span.getParents().get(0)); } zipkinSpan.id(span.getSpanId()); if (StringUtils.hasText(span.getName())) { zipkinSpan.name(span.getName()); } return zipkinSpan.build(); }
private static void ensureServerAddr(Span span, zipkin.Span.Builder zipkinSpan, Endpoint ep) { String serviceName = span.tags().containsKey(Span.SPAN_PEER_SERVICE_TAG_NAME) ? span.tags().get(Span.SPAN_PEER_SERVICE_TAG_NAME) : ep.serviceName; Endpoint endpoint = ep.port == null ? Endpoint.create(serviceName, ep.ipv4) : Endpoint.create(serviceName, ep.ipv4, ep.port); zipkinSpan.addBinaryAnnotation(BinaryAnnotation.address(Constants.SERVER_ADDR, endpoint)); }
private static void ensureLocalComponent(Span span, Builder zipkinSpan, Endpoint ep) { if (span.tags().containsKey(Constants.LOCAL_COMPONENT)) { return; } String processId = span.getProcessId() != null ? span.getProcessId().toLowerCase() : ZipkinMessageListener.UNKNOWN_PROCESS_ID; zipkinSpan.addBinaryAnnotation( BinaryAnnotation.create(Constants.LOCAL_COMPONENT, processId, ep)); }
static List<zipkin.Span> convert(Spans input) { Host host = input.getHost(); List<zipkin.Span> result = new ArrayList<>(input.getSpans().size()); for (Span span : input.getSpans()) { if (!span.getName().equals("message:" + SleuthSink.INPUT)) { result.add(convert(span, host)); } else { log.warn("Message tracing cycle detected for: " + input); } } return result; }
private MvcResult sendPingWithTraceId(String headerName, Long correlationId, boolean sampling) throws Exception { MockHttpServletRequestBuilder request = MockMvcRequestBuilders.get("/ping") .accept(MediaType.TEXT_PLAIN) .header(headerName, Span.toHex(correlationId)) .header(Span.SPAN_ID_NAME, Span.toHex(new Random().nextLong())); if (!sampling) { request.header(Span.NOT_SAMPLED_NAME, "true"); } return this.mockMvc.perform(request).andReturn(); }
@Test public void should_increment_dropped_spans_when_message_sending_was_successful() throws Exception { Span span1 = Span.builder().build(); Span span2 = Span.builder().build(); Message<Spans> message = MessageBuilder.withPayload(new Spans(null, Arrays.asList(span1, span2))).build(); this.tracerIgnoringChannelInterceptor.afterSendCompletion( message, this.messageChannel, false, null); BDDMockito.then(this.spanMetricReporter).should().incrementDroppedSpans(2); }
static void addPayloadAnnotations(TraceKeys traceKeys, Object payload, Span span) { if (payload != null) { span.tag( traceKeys.getMessage().getPayload().getType(), payload.getClass().getCanonicalName()); if (payload instanceof String) { span.tag( traceKeys.getMessage().getPayload().getSize(), String.valueOf(((String) payload).length())); } else if (payload instanceof byte[]) { span.tag( traceKeys.getMessage().getPayload().getSize(), String.valueOf(((byte[]) payload).length)); } } }
private static boolean notClientOrServer(Span span) { for (org.springframework.cloud.sleuth.Log log : span.logs()) { if (ZIPKIN_START_EVENTS.contains(log.getEvent())) { return false; } } return true; }
@Test public void when_not_sampling_header_present_span_is_not_exportable() throws Exception { Long expectedTraceId = new Random().nextLong(); MvcResult mvcResult = whenSentPingWithTraceIdAndNotSampling(expectedTraceId); then(tracingHeaderFrom(mvcResult)).isEqualTo(expectedTraceId); then(span.isExportable()).isFalse(); }
@Test public void when_always_sampler_is_used_span_is_exportable() throws Exception { Long expectedTraceId = new Random().nextLong(); MvcResult mvcResult = whenSentPingWithTraceId(expectedTraceId); then(tracingHeaderFrom(mvcResult)).isEqualTo(expectedTraceId); then(span.isExportable()); }
private Map<String, Collection<String>> headersWithTraceId( Map<String, Collection<String>> headers) { Map<String, Collection<String>> newHeaders = new HashMap<>(); newHeaders.putAll(headers); Span span = getCurrentSpan(); if (span == null) { setHeader(newHeaders, Trace.NOT_SAMPLED_NAME, ""); return newHeaders; } if (span.getSpanId() == null) { setHeader(newHeaders, Trace.TRACE_ID_NAME, span.getTraceId()); setHeader(newHeaders, Trace.NOT_SAMPLED_NAME, ""); return newHeaders; } setHeader(newHeaders, Trace.TRACE_ID_NAME, span.getTraceId()); setHeader(newHeaders, Trace.SPAN_ID_NAME, span.getSpanId()); setHeader(newHeaders, Trace.PARENT_ID_NAME, getParentId(span)); return newHeaders; }
/** returns a converted span or null if it is invalid or unsampled. */ io.zipkin.Span convertAndSample(Span input, Host host) { if (!input.getName().equals("message/" + SleuthSink.INPUT)) { io.zipkin.Span result = ZipkinMessageListener.convert(input, host); if (this.sampler.isSampled(result.traceId)) { return result; } } else { log.warn("Message tracing cycle detected for: " + input); } return null; }
public static void addAnnotations(TraceKeys traceKeys, Message<?> message, Span span) { for (String name : traceKeys.getMessage().getHeaders()) { if (message.getHeaders().containsKey(name)) { String key = traceKeys.getMessage().getPrefix() + name.toLowerCase(); Object value = message.getHeaders().get(name); if (value == null) { value = "null"; } span.tag(key, value.toString()); // TODO: better way to serialize? } } addPayloadAnnotations(traceKeys, message.getPayload(), span); }
private String getParentId(Span span) { return span.getParents() != null && !span.getParents().isEmpty() ? span.getParents().get(0) : null; }
private Long tracingHeaderFrom(MvcResult mvcResult) { return Span.fromHex(mvcResult.getResponse().getHeader(Span.TRACE_ID_NAME)); }
private static void addHeader(Map<String, String> headers, String name, Long value) { if (value != null) { addHeader(headers, name, Span.toHex(value)); } }