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));
   }
 }