diff --git a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java index 243d64859fa..71358bd7dfe 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java @@ -1083,24 +1083,32 @@ static final ReusableSingleSpanBuilder reuseSingleSpanBuilder( @Override public AgentSpan startSpan(final String instrumentationName, final CharSequence spanName) { - return singleSpanBuilder(instrumentationName, spanName).start(); + return CoreSpanBuilder.startSpan( + this, + instrumentationName, + spanName, + null, + CoreSpanBuilder.USE_SCOPE, + CoreSpanBuilder.AUTO_ASSIGN_TIMESTAMP); } @Override public AgentSpan startSpan( final String instrumentationName, final CharSequence spanName, final long startTimeMicros) { - return singleSpanBuilder(instrumentationName, spanName) - .withStartTimestamp(startTimeMicros) - .start(); + return CoreSpanBuilder.startSpan( + this, instrumentationName, spanName, null, CoreSpanBuilder.USE_SCOPE, startTimeMicros); } @Override public AgentSpan startSpan( String instrumentationName, final CharSequence spanName, final AgentSpanContext parent) { - return singleSpanBuilder(instrumentationName, spanName) - .ignoreActiveSpan() - .asChildOf(parent) - .start(); + return CoreSpanBuilder.startSpan( + this, + instrumentationName, + spanName, + parent, + CoreSpanBuilder.IGNORE_SCOPE, + CoreSpanBuilder.AUTO_ASSIGN_TIMESTAMP); } @Override @@ -1109,11 +1117,8 @@ public AgentSpan startSpan( final CharSequence spanName, final AgentSpanContext parent, final long startTimeMicros) { - return singleSpanBuilder(instrumentationName, spanName) - .ignoreActiveSpan() - .asChildOf(parent) - .withStartTimestamp(startTimeMicros) - .start(); + return CoreSpanBuilder.startSpan( + this, instrumentationName, spanName, parent, CoreSpanBuilder.IGNORE_SCOPE, startTimeMicros); } @Override @@ -1521,6 +1526,11 @@ private static Map invertMap(Map map) { /** Spans are built using this builder */ public abstract static class CoreSpanBuilder implements AgentTracer.SpanBuilder { + protected static final boolean USE_SCOPE = false; + protected static final boolean IGNORE_SCOPE = true; + protected static final int AUTO_ASSIGN_SPAN_ID = 0; + protected static final long AUTO_ASSIGN_TIMESTAMP = 0L; + protected final CoreTracer tracer; protected String instrumentationName; @@ -1535,12 +1545,12 @@ public abstract static class CoreSpanBuilder implements AgentTracer.SpanBuilder protected String resourceName; protected boolean errorFlag; protected CharSequence spanType; - protected boolean ignoreScope = false; + protected boolean ignoreScope = USE_SCOPE; protected Object builderRequestContextDataAppSec; protected Object builderRequestContextDataIast; protected Object builderCiVisibilityContextData; protected List links; - protected long spanId; + protected long spanId = AUTO_ASSIGN_SPAN_ID; // Make sure any fields added here are also reset properly in ReusableSingleSpanBuilder.reset CoreSpanBuilder(CoreTracer tracer) { @@ -1553,8 +1563,51 @@ public final CoreSpanBuilder ignoreActiveSpan() { return this; } - protected final DDSpan buildSpan() { - DDSpan span = DDSpan.create(instrumentationName, timestampMicro, buildSpanContext(), links); + protected static final DDSpan buildSpan( + final CoreTracer tracer, + long spanId, + String instrumentationName, + long timestampMicro, + String serviceName, + CharSequence operationName, + String resourceName, + AgentSpanContext resolvedParentContext, + boolean ignoreScope, + boolean errorFlag, + CharSequence spanType, + TagMap.Ledger tagLedger, + List links, + Object builderRequestContextDataAppSec, + Object builderRequestContextDataIast, + Object builderCiVisibilityContextData) { + return buildSpanImpl( + tracer, + instrumentationName, + timestampMicro, + links, + buildSpanContext( + tracer, + spanId, + serviceName, + operationName, + resourceName, + resolvedParentContext, + errorFlag, + spanType, + tagLedger, + links, + builderRequestContextDataAppSec, + builderRequestContextDataIast, + builderCiVisibilityContextData)); + } + + protected static final DDSpan buildSpanImpl( + CoreTracer tracer, + String instrumentationName, + long timestampMicro, + List links, + DDSpanContext spanContext) { + DDSpan span = DDSpan.create(instrumentationName, timestampMicro, spanContext, links); if (span.isLocalRootSpan()) { EndpointTracker tracker = tracer.onRootSpanStarted(span); if (tracker != null) { @@ -1564,7 +1617,8 @@ protected final DDSpan buildSpan() { return span; } - private final void addParentContextAsLinks(AgentSpanContext parentContext) { + private static final List addParentContextLink( + List links, AgentSpanContext parentContext) { SpanLink link; if (parentContext instanceof ExtractedContext) { String headers = ((ExtractedContext) parentContext).getPropagationStyle().toString(); @@ -1577,38 +1631,154 @@ private final void addParentContextAsLinks(AgentSpanContext parentContext) { } else { link = SpanLink.from(parentContext); } - withLink(link); + return addLink(links, link); } - private final void addTerminatedContextAsLinks() { - if (this.parent instanceof TagContext) { + protected static final List addTerminatedContextAsLinks( + List links, AgentSpanContext parentContext) { + if (parentContext instanceof TagContext) { List terminatedContextLinks = - ((TagContext) this.parent).getTerminatedContextLinks(); + ((TagContext) parentContext).getTerminatedContextLinks(); if (!terminatedContextLinks.isEmpty()) { - if (this.links == null) { - this.links = new ArrayList<>(); - } - this.links.addAll(terminatedContextLinks); + return addLinks(links, terminatedContextLinks); } } + return links; + } + + protected static final List addLink( + List links, AgentSpanLink link) { + if (links == null) links = new ArrayList<>(); + links.add(link); + return links; + } + + protected static final List addLinks( + List links, List additionalLinks) { + if (links == null) { + links = new ArrayList<>(additionalLinks); + } else { + links.addAll(additionalLinks); + } + return links; } @Override public abstract AgentSpan start(); protected AgentSpan startImpl() { - AgentSpanContext pc = parent; - if (pc == null && !ignoreScope) { - final AgentSpan span = tracer.activeSpan(); - if (span != null) { - pc = span.context(); + return startSpan( + this.tracer, + this.spanId, + this.instrumentationName, + this.timestampMicro, + this.serviceName, + this.operationName, + this.resourceName, + this.parent, + this.ignoreScope, + this.errorFlag, + this.spanType, + this.tagLedger, + this.links, + this.builderRequestContextDataAppSec, + this.builderRequestContextDataIast, + this.builderCiVisibilityContextData); + } + + protected static final AgentSpan startSpan( + final CoreTracer tracer, + String instrumentationName, + CharSequence operationName, + AgentSpanContext specifiedParentContext, + boolean ignoreScope, + long timestampMicros) { + return startSpan( + tracer, + AUTO_ASSIGN_SPAN_ID, + instrumentationName, + timestampMicros, + null /* serviceName */, + operationName, + null /* resourceName */, + specifiedParentContext, + ignoreScope, + false /* errorFlag */, + null /* spanType */, + null /* tagLedger */, + null /* links */, + null /* appSec */, + null /* iast */, + null /* ciViz */); + } + + protected static final AgentSpan startSpan( + final CoreTracer tracer, + long spanId, + String instrumentationName, + long timestampMicro, + String serviceName, + CharSequence operationName, + String resourceName, + AgentSpanContext specifiedParentContext, + boolean ignoreScope, + boolean errorFlag, + CharSequence spanType, + TagMap.Ledger tagLedger, + List links, + Object builderRequestContextDataAppSec, + Object builderRequestContextDataIast, + Object builderCiVisibilityContextData) { + // Find the parent context + AgentSpanContext parentContext = specifiedParentContext; + if (parentContext == null && !ignoreScope) { + // use the Scope as parent unless overridden or ignored. + final AgentSpan activeSpan = tracer.scopeManager.activeSpan(); + if (activeSpan != null) { + parentContext = activeSpan.context(); } } - if (pc == BlackHoleSpan.Context.INSTANCE) { - return new BlackHoleSpan(pc.getTraceId()); + if (parentContext == BlackHoleSpan.Context.INSTANCE) { + return new BlackHoleSpan(parentContext.getTraceId()); + } + + // Handle remote terminated context as span links + if (parentContext != null && parentContext.isRemote()) { + switch (Config.get().getTracePropagationBehaviorExtract()) { + case RESTART: + links = addParentContextLink(links, parentContext); + parentContext = null; + break; + + case IGNORE: + parentContext = null; + break; + + case CONTINUE: + default: + links = addTerminatedContextAsLinks(links, specifiedParentContext); + break; + } } - return buildSpan(); + + return buildSpan( + tracer, + spanId, + instrumentationName, + timestampMicro, + serviceName, + operationName, + resourceName, + parentContext, + ignoreScope, + errorFlag, + spanType, + tagLedger, + links, + builderRequestContextDataAppSec, + builderRequestContextDataIast, + builderCiVisibilityContextData); } @Override @@ -1733,10 +1903,22 @@ public final CoreSpanBuilder withSpanId(final long spanId) { * * @return the context */ - private final DDSpanContext buildSpanContext() { - final DDTraceId traceId; - final long spanId; - final long parentSpanId; + protected static final DDSpanContext buildSpanContext( + final CoreTracer tracer, + long spanId, + String serviceName, + CharSequence operationName, + String resourceName, + AgentSpanContext resolvedParentContext, + boolean errorFlag, + CharSequence spanType, + TagMap.Ledger tagLedger, + List links, + Object builderRequestContextDataAppSec, + Object builderRequestContextDataIast, + Object builderCiVisibilityContextData) { + DDTraceId traceId; + long parentSpanId; final Map baggage; final Baggage w3cBaggage; final TraceCollector parentTraceCollector; @@ -1753,43 +1935,16 @@ private final DDSpanContext buildSpanContext() { final PathwayContext pathwayContext; final PropagationTags propagationTags; - if (this.spanId == 0) { + if (spanId == AUTO_ASSIGN_SPAN_ID) { spanId = tracer.idGenerationStrategy.generateSpanId(); - } else { - spanId = this.spanId; - } - - // Find the parent context - AgentSpanContext parentContext = parent; - if (parentContext == null && !ignoreScope) { - // use the Scope as parent unless overridden or ignored. - final AgentSpan activeSpan = tracer.scopeManager.activeSpan(); - if (activeSpan != null) { - parentContext = activeSpan.context(); - } - } - // Handle remote terminated context as span links - if (parentContext != null && parentContext.isRemote()) { - switch (Config.get().getTracePropagationBehaviorExtract()) { - case RESTART: - addParentContextAsLinks(parentContext); - parentContext = null; - break; - case IGNORE: - parentContext = null; - break; - case CONTINUE: - default: - addTerminatedContextAsLinks(); - } } String parentServiceName = null; // Propagate internal trace. // Note: if we are not in the context of distributed tracing, and we are starting the first // root span, parentContext will be null at this point. - if (parentContext instanceof DDSpanContext) { - final DDSpanContext ddsc = (DDSpanContext) parentContext; + if (resolvedParentContext instanceof DDSpanContext) { + final DDSpanContext ddsc = (DDSpanContext) resolvedParentContext; traceId = ddsc.getTraceId(); parentSpanId = ddsc.getSpanId(); baggage = ddsc.getBaggageItems(); @@ -1805,7 +1960,7 @@ private final DDSpanContext buildSpanContext() { if (serviceName == null) { serviceName = parentServiceName; } - RequestContext requestContext = ((DDSpanContext) parentContext).getRequestContext(); + RequestContext requestContext = ((DDSpanContext) resolvedParentContext).getRequestContext(); if (requestContext != null) { requestContextDataAppSec = requestContext.getData(RequestContextSlot.APPSEC); requestContextDataIast = requestContext.getData(RequestContextSlot.IAST); @@ -1819,21 +1974,21 @@ private final DDSpanContext buildSpanContext() { } else { long endToEndStartTime; - if (parentContext instanceof ExtractedContext) { + if (resolvedParentContext instanceof ExtractedContext) { // Propagate external trace - final ExtractedContext extractedContext = (ExtractedContext) parentContext; + final ExtractedContext extractedContext = (ExtractedContext) resolvedParentContext; traceId = extractedContext.getTraceId(); parentSpanId = extractedContext.getSpanId(); samplingPriority = extractedContext.getSamplingPriority(); endToEndStartTime = extractedContext.getEndToEndStartTime(); propagationTags = extractedContext.getPropagationTags(); - } else if (parentContext != null) { + } else if (resolvedParentContext != null) { traceId = - parentContext.getTraceId() == DDTraceId.ZERO + resolvedParentContext.getTraceId() == DDTraceId.ZERO ? tracer.idGenerationStrategy.generateTraceId() - : parentContext.getTraceId(); - parentSpanId = parentContext.getSpanId(); - samplingPriority = parentContext.getSamplingPriority(); + : resolvedParentContext.getTraceId(); + parentSpanId = resolvedParentContext.getSpanId(); + samplingPriority = resolvedParentContext.getSamplingPriority(); endToEndStartTime = 0; propagationTags = tracer.propagationTagsFactory.empty(); } else { @@ -1848,8 +2003,8 @@ private final DDSpanContext buildSpanContext() { ConfigSnapshot traceConfig; // Get header tags and set origin whether propagating or not. - if (parentContext instanceof TagContext) { - TagContext tc = (TagContext) parentContext; + if (resolvedParentContext instanceof TagContext) { + TagContext tc = (TagContext) resolvedParentContext; traceConfig = (ConfigSnapshot) tc.getTraceConfig(); coreTags = tc.getTags(); coreTagsNeedsIntercept = true; // maybe intercept isn't needed? @@ -1885,10 +2040,10 @@ private final DDSpanContext buildSpanContext() { // Use parent pathwayContext if present and started pathwayContext = - parentContext != null - && parentContext.getPathwayContext() != null - && parentContext.getPathwayContext().isStarted() - ? parentContext.getPathwayContext() + resolvedParentContext != null + && resolvedParentContext.getPathwayContext() != null + && resolvedParentContext.getPathwayContext().isStarted() + ? resolvedParentContext.getPathwayContext() : tracer.dataStreamsMonitoring.newPathwayContext(); // when removing fake services the best upward service name to pick is the local root one @@ -1920,8 +2075,9 @@ private final DDSpanContext buildSpanContext() { serviceName = tracer.serviceName; } - final CharSequence operationName = - this.operationName != null ? this.operationName : resourceName; + if (operationName == null) { + operationName = resourceName; + } final TagMap mergedTracerTags = traceConfig.mergedTracerTags; boolean mergedTracerTagsNeedsIntercept = traceConfig.mergedTracerTagsNeedsIntercept;