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 28f9e39c710..ba88574b375 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 @@ -72,6 +72,7 @@ import datadog.trace.bootstrap.instrumentation.api.ProfilingContextIntegration; import datadog.trace.bootstrap.instrumentation.api.SpanAttributes; import datadog.trace.bootstrap.instrumentation.api.SpanLink; +import datadog.trace.bootstrap.instrumentation.api.SpanPrototype; import datadog.trace.bootstrap.instrumentation.api.TagContext; import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.civisibility.interceptor.CiVisibilityApmProtocolInterceptor; @@ -1038,6 +1039,24 @@ public CoreSpanBuilder buildSpan( return createMultiSpanBuilder(instrumentationName, operationName); } + /** + * Seeds identity (instrumentation name, operation, span type) and tags from a prototype. + * + *

TODO(follow-up): eager-sets identity from the proto today, which is fine while + * {@code buildSpan(proto)} is the only proto entry point. When a builder value and a proto value + * can coexist, resolve via helpers (builder-explicit wins, proto is the fallback) in the build + * path and make this carry-only — no reach-in to {@code builder.spanType}/{@code spanPrototype}. + */ + public CoreSpanBuilder buildSpan(final SpanPrototype prototype) { + CoreSpanBuilder builder = + createMultiSpanBuilder(prototype.instrumentationName(), prototype.operationName()); + builder.spanPrototype = prototype; + if (prototype.spanType() != null) { + builder.spanType = prototype.spanType(); + } + return builder; + } + MultiSpanBuilder createMultiSpanBuilder( final String instrumentationName, final CharSequence operationName) { return new MultiSpanBuilder(this, instrumentationName, operationName); @@ -1583,6 +1602,7 @@ public abstract static class CoreSpanBuilder implements AgentTracer.SpanBuilder // Builder attributes // Make sure any fields added here are also reset properly in ReusableSingleSpanBuilder.reset protected TagMap.Ledger tagLedger; + protected SpanPrototype spanPrototype = SpanPrototype.NONE; protected long timestampMicro; protected AgentSpanContext parent; protected String serviceName; @@ -1621,6 +1641,7 @@ protected static final DDSpan buildSpan( boolean errorFlag, CharSequence spanType, TagMap.Ledger tagLedger, + SpanPrototype spanPrototype, List links, Object builderRequestContextDataAppSec, Object builderRequestContextDataIast, @@ -1640,6 +1661,7 @@ protected static final DDSpan buildSpan( errorFlag, spanType, tagLedger, + spanPrototype, links, builderRequestContextDataAppSec, builderRequestContextDataIast, @@ -1725,6 +1747,7 @@ protected AgentSpan startImpl() { this.errorFlag, this.spanType, this.tagLedger, + this.spanPrototype, this.links, this.builderRequestContextDataAppSec, this.builderRequestContextDataIast, @@ -1751,6 +1774,7 @@ protected static final AgentSpan startSpan( false /* errorFlag */, null /* spanType */, null /* tagLedger */, + SpanPrototype.NONE /* spanPrototype */, null /* links */, null /* appSec */, null /* iast */, @@ -1770,6 +1794,7 @@ protected static final AgentSpan startSpan( boolean errorFlag, CharSequence spanType, TagMap.Ledger tagLedger, + SpanPrototype spanPrototype, List links, Object builderRequestContextDataAppSec, Object builderRequestContextDataIast, @@ -1820,6 +1845,7 @@ protected static final AgentSpan startSpan( errorFlag, spanType, tagLedger, + spanPrototype, links, builderRequestContextDataAppSec, builderRequestContextDataIast, @@ -1958,6 +1984,7 @@ protected static final DDSpanContext buildSpanContext( boolean errorFlag, CharSequence spanType, TagMap.Ledger tagLedger, + SpanPrototype spanPrototype, List links, Object builderRequestContextDataAppSec, Object builderRequestContextDataIast, @@ -2196,6 +2223,9 @@ protected static final DDSpanContext buildSpanContext( // the builder. This is the order that the tags were added previously, but maybe the `tags` // set in the builder should come last, so that they override other tags. context.setAllTags(mergedTracerTags, mergedTracerTagsNeedsIntercept); + if (spanPrototype != SpanPrototype.NONE) { + context.setAllTags(spanPrototype.tags()); + } context.setAllTags(tagLedger); context.setAllTags(coreTags, coreTagsNeedsIntercept); context.setAllTags(rootSpanTags, rootSpanTagsNeedsIntercept); @@ -2276,6 +2306,7 @@ final boolean reset(String instrumentationName, CharSequence operationName) { this.operationName = operationName; if (this.tagLedger != null) this.tagLedger.reset(); + this.spanPrototype = SpanPrototype.NONE; this.timestampMicro = 0L; this.parent = null; this.serviceName = null;