All Downloads are FREE. Search and download functionalities are using the official Maven repository.

datadog.trace.finagle.ServerTraceInitializer Maven / Gradle / Ivy

package datadog.trace.finagle;

import com.twitter.finagle.Filter;
import com.twitter.finagle.ServiceFactory;
import com.twitter.finagle.Stack;
import com.twitter.finagle.http.HttpTracing.Header$;
import com.twitter.finagle.http.Request;
import com.twitter.finagle.http.TraceInfo;
import com.twitter.finagle.param.Tracer;
import com.twitter.finagle.tracing.Flags;
import com.twitter.finagle.tracing.SpanId;
import com.twitter.finagle.tracing.Trace;
import com.twitter.finagle.tracing.TraceId;
import com.twitter.finagle.tracing.TraceId128;
import com.twitter.finagle.tracing.TraceInitializerFilter;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import scala.Option;

/** Extracts trace ids from incoming requests and applies it to the local trace */
public class ServerTraceInitializer
    extends Stack.Module1> {
  public ServerTraceInitializer() {
    super(Tracer.param());
  }

  @Override
  public Stack.Role role() {
    return TraceInitializerFilter.role();
  }

  @Override
  public String description() {
    return "Extracts trace ids from incoming requests";
  }

  @Override
  public ServiceFactory make(Tracer tracer, ServiceFactory next) {

    Filter filter =
        Filter.mk(
            (req, service) ->
                Trace.letTracer(
                    Tracer.unapply(tracer).get(),
                    () -> letTraceIdFromRequestHeaders(req, () -> service.apply(req))));

    return filter.andThen(next);
  }

  // This is a reimplementation of com.twitter.finagle.http.TraceInfo that creates a new span
  // id for the server span
  private  R letTraceIdFromRequestHeaders(Request request, Supplier f) {
    TraceInfo.convertB3Trace(request);

    TraceId traceId = null;

    if (Header$.MODULE$.hasAllRequired(request.headerMap())) {
      // Assign spanId to parent span id!!
      Option parentSpanId =
          SpanId.fromString((String) request.headerMap().apply(Header$.MODULE$.SpanId()));

      if (parentSpanId.isDefined()) {
        TraceId128 trace128Bit =
            TraceId128.apply((String) request.headerMap().apply(Header$.MODULE$.TraceId()));

        String maybeSampled = request.headerMap().getOrNull(Header$.MODULE$.Sampled());
        boolean sampled = "1".equals(maybeSampled) || Boolean.parseBoolean(maybeSampled);

        Flags flags = TraceInfo.getFlags(request);

        traceId =
            TraceId.apply(
                trace128Bit.low(),
                parentSpanId,
                newSpanId(),
                Option.apply(sampled),
                flags,
                trace128Bit.high(),
                false);
      } else {
        traceId = Trace.nextId();
      }

    } else if (request.headerMap().contains(Header$.MODULE$.Flags())) {
      traceId = traceIdWithFlag(Trace.nextId(), TraceInfo.getFlags(request));
    } else {
      traceId = Trace.nextId();
    }

    Header$.MODULE$.All().foreach((h) -> request.headerMap().remove(h));

    if (traceId != null) {
      return Trace.letId(
          traceId,
          false,
          () -> {
            TraceInfo.traceRpc(request);
            return f.get();
          });
    } else {
      TraceInfo.traceRpc(request);
      return f.get();
    }
  }

  private static TraceId traceIdWithFlag(TraceId orig, Flags flags) {
    return new TraceId(
        orig._traceId(),
        orig._parentId(),
        orig.spanId(),
        orig._sampled(),
        flags,
        orig.traceIdHigh(),
        orig.terminal());
  }

  private static SpanId newSpanId() {
    long nextId = ThreadLocalRandom.current().nextLong(1, Long.MAX_VALUE);
    return SpanId.apply(nextId);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy