diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java index 772cbe90866..2c2e5d9d1f2 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpan.java @@ -116,7 +116,8 @@ static DDSpan create( */ private volatile int longRunningVersion = 0; - protected final List links; + private static final List EMPTY = Collections.emptyList(); + protected volatile List links; /** * Spans should be constructed using the builder, not by calling the constructor directly. @@ -144,7 +145,7 @@ private DDSpan( context.getTraceCollector().touch(); // external clock: explicitly update lastReferenced } - this.links = links == null ? new CopyOnWriteArrayList<>() : new CopyOnWriteArrayList<>(links); + this.links = links == null || links.isEmpty() ? EMPTY : new CopyOnWriteArrayList<>(links); } public boolean isFinished() { @@ -764,12 +765,12 @@ public CharSequence getType() { @Override public void processServiceTags() { - context.earlyProcessTags(links); + context.earlyProcessTags(this); } @Override public void processTagsAndBaggage(final MetadataConsumer consumer) { - context.processTagsAndBaggage(consumer, longRunningVersion, links); + context.processTagsAndBaggage(consumer, longRunningVersion, this); } @Override @@ -883,10 +884,44 @@ public TraceConfig traceConfig() { return context.getTraceCollector().getTraceConfig(); } + List getLinks() { + return this.links; + } + @Override public void addLink(AgentSpanLink link) { - if (link != null) { - this.links.add(link); + if (link == null) { + return; + } + + // If links are initially null / empty, then the shared placeholder List EMPTY is used. + // Bacause EMPTY is shared, EMPTY is safe for reading, but not for writing. + // On write - if links is the EMPTY placeholder, then need to create a CopyOnWriteArrayList + // owned by this DDSpan + + // Creation of the CopyOnWriteArrayList is done via double checking locking using volatile & + // synchronized + + // If before or inside the synchronized block, links no longer points to EMPTY, + // then this thread or another thread has already handled the list construction, + // so just add to the list + + // If links still points to EMPTY inside the synchronized block, then construct a new + // CopyOnWriteArrayList containing the newly added link + + List links = this.links; + if (links != EMPTY) { + links.add(link); + return; + } + + synchronized (this) { + links = this.links; + if (links != EMPTY) { + links.add(link); + } else { + this.links = new CopyOnWriteArrayList<>(Collections.singletonList(link)); + } } } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java index a17d7684a71..2b8dbccb738 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanContext.java @@ -24,7 +24,7 @@ import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.api.sampling.SamplingMechanism; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.bootstrap.instrumentation.api.Baggage; import datadog.trace.bootstrap.instrumentation.api.ProfilerContext; import datadog.trace.bootstrap.instrumentation.api.ProfilingContextIntegration; @@ -1087,19 +1087,24 @@ public void setMetaStruct(final String field, final T value) { } } - public void earlyProcessTags(List links) { + void earlyProcessTags(AppendableSpanLinks links) { synchronized (unsafeTags) { TagsPostProcessorFactory.eagerProcessor().processTags(unsafeTags, this, links); } } - public void processTagsAndBaggage( - final MetadataConsumer consumer, int longRunningVersion, List links) { + void processTagsAndBaggage( + final MetadataConsumer consumer, int longRunningVersion, DDSpan restrictedSpan) { + // NOTE: The span is passed for the sole purpose of allowing updating & reading of the span + // links + // This is a compromise to avoid... + // - creating an extra wrapper object that would create significant allocation + // - implementing an interface to read the spans that require making the read method public synchronized (unsafeTags) { // Tags - TagsPostProcessorFactory.lazyProcessor().processTags(unsafeTags, this, links); + TagsPostProcessorFactory.lazyProcessor().processTags(unsafeTags, this, restrictedSpan); - String linksTag = DDSpanLink.toTag(links); + String linksTag = DDSpanLink.toTag(restrictedSpan.getLinks()); if (linksTag != null) { unsafeTags.put(SPAN_LINKS, linksTag); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanLink.java b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanLink.java index d6c16c7b02e..efcaafc7016 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/DDSpanLink.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/DDSpanLink.java @@ -69,7 +69,7 @@ public static SpanLink from(ExtractedContext context, SpanAttributes attributes) * @param links The span link collection to encode. * @return The encoded tag value, {@code null} if no links. */ - public static String toTag(List links) { + public static String toTag(List links) { if (links == null || links.isEmpty()) { return null; } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/HttpEndpointPostProcessor.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/HttpEndpointPostProcessor.java index 05ff83d8fda..340a5d82649 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/HttpEndpointPostProcessor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/HttpEndpointPostProcessor.java @@ -6,9 +6,8 @@ import datadog.trace.api.TagMap; import datadog.trace.api.endpoint.EndpointResolver; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.core.DDSpanContext; -import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,7 +55,7 @@ public HttpEndpointPostProcessor() { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { if (!endpointResolver.isEnabled()) { log.debug("EndpointResolver is not enabled, skipping HTTP endpoint post processing"); return; diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/IntegrationAdder.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/IntegrationAdder.java index 87024d057bd..0aabbc29c47 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/IntegrationAdder.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/IntegrationAdder.java @@ -3,14 +3,13 @@ import static datadog.trace.api.DDTags.DD_INTEGRATION; import datadog.trace.api.TagMap; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.core.DDSpanContext; -import java.util.List; public class IntegrationAdder extends TagsPostProcessor { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { final CharSequence instrumentationName = spanContext.getIntegrationName(); if (instrumentationName != null) { unsafeTags.set(DD_INTEGRATION, instrumentationName); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/InternalTagsAdder.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/InternalTagsAdder.java index 6fed132a68f..68b13d19faf 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/InternalTagsAdder.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/InternalTagsAdder.java @@ -4,10 +4,9 @@ import datadog.trace.api.DDTags; import datadog.trace.api.TagMap; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.core.DDSpanContext; -import java.util.List; import javax.annotation.Nullable; public final class InternalTagsAdder extends TagsPostProcessor { @@ -21,7 +20,7 @@ public InternalTagsAdder(@Nullable final String ddService, @Nullable final Strin @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { if (spanContext == null || ddService == null) { return; } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java index c04c8239e44..0fdb962aa12 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PayloadTagsProcessor.java @@ -7,7 +7,7 @@ import datadog.trace.api.ConfigDefaults; import datadog.trace.api.TagMap; import datadog.trace.api.telemetry.LogCollector; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.core.DDSpanContext; import datadog.trace.core.util.JsonStreamParser; import datadog.trace.payloadtags.PayloadTagsData; @@ -72,7 +72,7 @@ public static PayloadTagsProcessor create(Config config) { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { int spanMaxTags = maxTags + unsafeTags.size(); for (Map.Entry tagPrefixRedactionRules : redactionRulesByTagPrefix.entrySet()) { diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PeerServiceCalculator.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PeerServiceCalculator.java index 9a4e9377cb9..ed1fee8b2d6 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PeerServiceCalculator.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PeerServiceCalculator.java @@ -5,10 +5,9 @@ import datadog.trace.api.TagMap; import datadog.trace.api.naming.NamingSchema; import datadog.trace.api.naming.SpanNaming; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.core.DDSpanContext; -import java.util.List; import java.util.Map; import javax.annotation.Nonnull; @@ -34,7 +33,7 @@ public PeerServiceCalculator() { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { Object peerService = unsafeTags.getObject(Tags.PEER_SERVICE); // the user set it if (peerService != null) { diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PostProcessorChain.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PostProcessorChain.java index 77374d742cb..2a2668e1b6b 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PostProcessorChain.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/PostProcessorChain.java @@ -1,9 +1,8 @@ package datadog.trace.core.tagprocessor; import datadog.trace.api.TagMap; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.core.DDSpanContext; -import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; @@ -16,7 +15,7 @@ public PostProcessorChain(@Nonnull final TagsPostProcessor... processors) { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { for (final TagsPostProcessor tagsPostProcessor : chain) { tagsPostProcessor.processTags(unsafeTags, spanContext, spanLinks); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/QueryObfuscator.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/QueryObfuscator.java index 37bbd470596..a1594e33eb6 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/QueryObfuscator.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/QueryObfuscator.java @@ -5,11 +5,10 @@ import com.google.re2j.PatternSyntaxException; import datadog.trace.api.DDTags; import datadog.trace.api.TagMap; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.core.DDSpanContext; import datadog.trace.util.Strings; -import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,7 +58,7 @@ private String obfuscate(String query) { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { Object query = unsafeTags.getObject(DDTags.HTTP_QUERY); if (query instanceof CharSequence) { query = obfuscate(query.toString()); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/RemoteHostnameAdder.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/RemoteHostnameAdder.java index 7bd45cd2c92..41947b375d8 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/RemoteHostnameAdder.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/RemoteHostnameAdder.java @@ -2,9 +2,8 @@ import datadog.trace.api.DDTags; import datadog.trace.api.TagMap; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.core.DDSpanContext; -import java.util.List; import java.util.function.Supplier; public final class RemoteHostnameAdder extends TagsPostProcessor { @@ -16,7 +15,7 @@ public RemoteHostnameAdder(Supplier hostnameSupplier) { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { if (spanContext.getSpanId() == spanContext.getRootSpanId()) { unsafeTags.put(DDTags.TRACER_HOST, hostnameSupplier.get()); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ServiceNameSourceAdder.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ServiceNameSourceAdder.java index 0d1eb95a570..4b081889039 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ServiceNameSourceAdder.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/ServiceNameSourceAdder.java @@ -3,14 +3,13 @@ import static datadog.trace.api.DDTags.DD_SVC_SRC; import datadog.trace.api.TagMap; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.core.DDSpanContext; -import java.util.List; public class ServiceNameSourceAdder extends TagsPostProcessor { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { final CharSequence serviceNameSource = spanContext.getServiceNameSource(); if (serviceNameSource != null) { unsafeTags.set(DD_SVC_SRC, serviceNameSource); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/SpanPointersProcessor.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/SpanPointersProcessor.java index 8282583cbf2..b0d252db980 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/SpanPointersProcessor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/SpanPointersProcessor.java @@ -13,6 +13,7 @@ import datadog.trace.api.TagMap; import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.bootstrap.instrumentation.api.SpanAttributes; import datadog.trace.bootstrap.instrumentation.api.SpanLink; import datadog.trace.core.DDSpanContext; @@ -21,7 +22,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; -import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,16 +38,16 @@ public class SpanPointersProcessor extends TagsPostProcessor { @Override public void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { // DQH - TODO - There's a lot room to optimize this using TagMap's capabilities AgentSpanLink s3Link = handleS3SpanPointer(unsafeTags); if (s3Link != null) { - spanLinks.add(s3Link); + spanLinks.addLink(s3Link); } AgentSpanLink dynamoDbLink = handleDynamoDbSpanPointer(unsafeTags); if (dynamoDbLink != null) { - spanLinks.add(dynamoDbLink); + spanLinks.addLink(dynamoDbLink); } } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessor.java b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessor.java index d0acedb40ee..e0c27e50aec 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessor.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/tagprocessor/TagsPostProcessor.java @@ -1,23 +1,10 @@ package datadog.trace.core.tagprocessor; import datadog.trace.api.TagMap; -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks; import datadog.trace.core.DDSpanContext; -import java.util.List; -import java.util.Map; public abstract class TagsPostProcessor { - /* - * DQH - For testing purposes only - */ - @Deprecated - final Map processTags( - Map unsafeTags, DDSpanContext context, List links) { - TagMap map = TagMap.fromMap(unsafeTags); - this.processTags(map, context, links); - return map; - } - public abstract void processTags( - TagMap unsafeTags, DDSpanContext spanContext, List spanLinks); + TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks); } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/HttpEndpointPostProcessorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/HttpEndpointPostProcessorTest.groovy index f343620dd48..ca43d9b6236 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/HttpEndpointPostProcessorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/HttpEndpointPostProcessorTest.groovy @@ -2,6 +2,7 @@ package datadog.trace.core.tagprocessor import datadog.trace.api.TagMap import datadog.trace.bootstrap.instrumentation.api.Tags +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks import datadog.trace.core.DDSpanContext import datadog.trace.api.endpoint.EndpointResolver import spock.lang.Specification @@ -15,6 +16,7 @@ class HttpEndpointPostProcessorTest extends Specification { def endpointResolver = new EndpointResolver(true, false) def processor = new HttpEndpointPostProcessor(endpointResolver) def mockContext = Mock(DDSpanContext) + def mockSpanLinks = Mock(AppendableSpanLinks) def tags = TagMap.fromMap([ (Tags.HTTP_METHOD): "GET", (Tags.HTTP_ROUTE): "/greeting", @@ -22,7 +24,7 @@ class HttpEndpointPostProcessorTest extends Specification { ]) when: - processor.processTags(tags, mockContext, []) + processor.processTags(tags, mockContext, mockSpanLinks) then: 0 * mockContext.setResourceName(_, _) @@ -35,6 +37,7 @@ class HttpEndpointPostProcessorTest extends Specification { def endpointResolver = new EndpointResolver(true, false) def processor = new HttpEndpointPostProcessor(endpointResolver) def mockContext = Mock(DDSpanContext) + def mockSpanLinks = Mock(AppendableSpanLinks) def tags = TagMap.fromMap([ (Tags.HTTP_METHOD): "GET", (Tags.HTTP_ROUTE): "*", // catch-all — ineligible per RFC-1051 @@ -42,7 +45,7 @@ class HttpEndpointPostProcessorTest extends Specification { ]) when: - processor.processTags(tags, mockContext, []) + processor.processTags(tags, mockContext, mockSpanLinks) then: 0 * mockContext.setResourceName(_, _) @@ -54,12 +57,13 @@ class HttpEndpointPostProcessorTest extends Specification { def endpointResolver = new EndpointResolver(true, false) def processor = new HttpEndpointPostProcessor(endpointResolver) def mockContext = Mock(DDSpanContext) - def tags = [ + def mockSpanLinks = Mock(AppendableSpanLinks) + def tags = TagMap.fromMap([ "db.statement": "SELECT * FROM users" - ] + ]) when: - processor.processTags(tags, mockContext, []) + processor.processTags(tags, mockContext, mockSpanLinks) then: 0 * mockContext.setResourceName(_, _) @@ -71,13 +75,14 @@ class HttpEndpointPostProcessorTest extends Specification { def endpointResolver = new EndpointResolver(false, false) def processor = new HttpEndpointPostProcessor(endpointResolver) def mockContext = Mock(DDSpanContext) - def tags = [ + def mockSpanLinks = Mock(AppendableSpanLinks) + def tags = TagMap.fromMap([ (Tags.HTTP_METHOD): "GET", (Tags.HTTP_ROUTE): "/greeting" - ] + ]) when: - processor.processTags(tags, mockContext, []) + processor.processTags(tags, mockContext, mockSpanLinks) then: 0 * mockContext.setResourceName(_, _) @@ -89,6 +94,7 @@ class HttpEndpointPostProcessorTest extends Specification { def endpointResolver = new EndpointResolver(true, true) def processor = new HttpEndpointPostProcessor(endpointResolver) def mockContext = Mock(DDSpanContext) + def mockSpanLinks = Mock(AppendableSpanLinks) def tags = TagMap.fromMap([ (Tags.HTTP_METHOD): "GET", (Tags.HTTP_ROUTE): "/greeting", @@ -96,7 +102,7 @@ class HttpEndpointPostProcessorTest extends Specification { ]) when: - processor.processTags(tags, mockContext, []) + processor.processTags(tags, mockContext, mockSpanLinks) then: 0 * mockContext.setResourceName(_, _) diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/IntegrationAdderTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/IntegrationAdderTest.groovy index 1e044aebfec..e8a17de339f 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/IntegrationAdderTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/IntegrationAdderTest.groovy @@ -1,6 +1,6 @@ package datadog.trace.core.tagprocessor - +import datadog.trace.api.TagMap import datadog.trace.core.DDSpanContext import datadog.trace.test.util.DDSpecification @@ -11,14 +11,14 @@ class IntegrationAdderTest extends DDSpecification { def spanContext = Mock(DDSpanContext) when: - - def enrichedTags = calculator.processTags(["_dd.integration": "bad"], spanContext, []) + def unsafeTags = TagMap.fromMap(["_dd.integration": "bad"]) + calculator.processTags(unsafeTags, spanContext, {link -> }) then: 1 * spanContext.getIntegrationName() >> (isSet ? "test" : null) and: - assert enrichedTags == (isSet ? ["_dd.integration": "test"] : [:]) + assert unsafeTags == (isSet ? ["_dd.integration": "test"] : [:]) where: isSet << [true, false] diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/InternalTagsAdderTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/InternalTagsAdderTest.groovy index 6416b23e67e..5429a9e8b24 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/InternalTagsAdderTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/InternalTagsAdderTest.groovy @@ -2,6 +2,8 @@ package datadog.trace.core.tagprocessor import static datadog.trace.bootstrap.instrumentation.api.Tags.VERSION +import datadog.trace.api.TagMap +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString import datadog.trace.core.DDSpanContext import datadog.trace.test.util.DDSpecification @@ -11,15 +13,17 @@ class InternalTagsAdderTest extends DDSpecification { setup: def calculator = new InternalTagsAdder("test", null) def spanContext = Mock(DDSpanContext) + def links = Mock(AppendableSpanLinks) when: - def enrichedTags = calculator.processTags([:], spanContext, []) + def unsafeTags = TagMap.fromMap([:]) + calculator.processTags(unsafeTags, spanContext, links) then: 1 * spanContext.getServiceName() >> serviceName and: - assert enrichedTags == expectedTags + assert unsafeTags == expectedTags where: serviceName | expectedTags @@ -32,15 +36,17 @@ class InternalTagsAdderTest extends DDSpecification { setup: def calculator = new InternalTagsAdder("same", ddVersion) def spanContext = Mock(DDSpanContext) + def links = Mock(AppendableSpanLinks) when: - def enrichedTags = calculator.processTags(tags, spanContext, []) + def unsafeTags = TagMap.fromMap(tags) + calculator.processTags(unsafeTags, spanContext, links) then: 1 * spanContext.getServiceName() >> serviceName and: - assert enrichedTags?.get(VERSION)?.toString() == expected + assert unsafeTags?.get(VERSION)?.toString() == expected where: diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy index b5f97c053ca..5b871052d99 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PayloadTagsProcessorTest.groovy @@ -6,6 +6,7 @@ import datadog.trace.payloadtags.PayloadTagsData.PathAndValue import datadog.trace.util.json.PathCursor import datadog.trace.test.util.DDSpecification import datadog.trace.api.Config +import datadog.trace.api.TagMap import okio.Buffer import java.time.Instant @@ -81,8 +82,12 @@ class PayloadTagsProcessorTest extends DDSpecification { "payload": new PayloadTagsData([] as PathAndValue[]) ] - expect: - ptp.processTags(spanTags, null, []) == ["foo": "bar", "tag1": 1] + when: + def unsafeTags = TagMap.fromMap(spanTags) + ptp.processTags(unsafeTags, null, {link -> }) + + then: + unsafeTags == ["foo": "bar", "tag1": 1] } static PathAndValue pv(PathCursor path, Object value) { @@ -106,8 +111,12 @@ class PayloadTagsProcessorTest extends DDSpecification { "payload": payloadData([pv(pc().push("tag1"), 0)]) ] - expect: - ptp.processTags(spanTags, null, []) == ["foo": "bar", "tag1": 1, "payload.tag1": 0] + when: + def unsafeTags = TagMap.fromMap(spanTags) + ptp.processTags(unsafeTags, null, {link -> }) + + then: + unsafeTags == ["foo": "bar", "tag1": 1, "payload.tag1": 0] } def "expand preserving tag types"() { @@ -123,8 +132,12 @@ class PayloadTagsProcessorTest extends DDSpecification { pv(pc().push("tag6"), false), ]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link -> }) + + then: + unsafeTags == [ "payload.tag1": 11, "payload.tag2.Value": 2342l, "payload.tag3.0": 3.14d, @@ -141,8 +154,12 @@ class PayloadTagsProcessorTest extends DDSpecification { def st = spanTags("payload", [pv(pc().push("tag7"), unknownValue),]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ "payload.tag7": unknownValue.toString(), ] } @@ -158,8 +175,12 @@ class PayloadTagsProcessorTest extends DDSpecification { pv(pc().push("j4"), "{'foo': 'bar', 'baz': 42}"), ]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ "p.j3.0": "1", "p.j3.1": 2, "p.j3.2": 3.14d, @@ -203,8 +224,12 @@ class PayloadTagsProcessorTest extends DDSpecification { def st = spanTags("dd", [pv(pc(), json),]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ 'dd.a' : 33, 'dd.Message.id' : 45, 'dd.Message.user.a' : 1.15d, @@ -219,8 +244,12 @@ class PayloadTagsProcessorTest extends DDSpecification { def st = spanTags("p", [pv(pc().push("key"), invalidJson),]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ "p.key": invalidJson, ] @@ -245,8 +274,12 @@ class PayloadTagsProcessorTest extends DDSpecification { pv(pc().push("j2"), new ByteArrayInputStream("[1, true]".bytes)), ]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ "p.j1.foo": "bar", "p.j2.0": 1, "p.j2.1": true, @@ -260,8 +293,11 @@ class PayloadTagsProcessorTest extends DDSpecification { when: def st = spanTags("p", [pv(pc().push("v"), new ByteArrayInputStream("""{ "inner": $innerJson}""".bytes))]) + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + then: - ptp.processTags(st, null, []) == [ + unsafeTags == [ "p.v.inner.a": 1.15d, "p.v.inner.password": "my-secret-password", ] @@ -282,8 +318,12 @@ class PayloadTagsProcessorTest extends DDSpecification { def st = spanTags("p", [pv(pc().push("key"), new ByteArrayInputStream(invalidJson.bytes)),]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ "p.key": "", ] @@ -302,8 +342,12 @@ class PayloadTagsProcessorTest extends DDSpecification { pv(pc().push("j4"), "{'foo': 'bar', 'baz': 42}"), ]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ "p.j3.0": "redacted", "p.j3.1": 2, "p.j3.2": 3.14d, @@ -325,8 +369,12 @@ class PayloadTagsProcessorTest extends DDSpecification { pv(pc().push("j4"), "{'foo': 'bar', 'baz': 42}"), ]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link ->}) + + then: + unsafeTags == [ "p.j3.0": "redacted", "p.j3.1": 2, "p.j3.2": 3.14d, @@ -344,8 +392,12 @@ class PayloadTagsProcessorTest extends DDSpecification { pv(pc().push("j4"), "{'foo': 'bar', 'baz': 42, 'nested': { 'a': 1, 'b': { 'c': 2 } } }"), ]) - expect: - ptp.processTags(st, null, []) == [ + when: + def unsafeTags = TagMap.fromMap(st) + ptp.processTags(unsafeTags, null, {link -> }) + + then: + unsafeTags == [ "p.j3.0": "redacted", "p.j3.1": 2, "p.j3.2": 3.14d, diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PeerServiceCalculatorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PeerServiceCalculatorTest.groovy index bc8281835bb..2ddf8770d1e 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PeerServiceCalculatorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PeerServiceCalculatorTest.groovy @@ -2,6 +2,7 @@ package datadog.trace.core.tagprocessor import datadog.trace.api.Config import datadog.trace.api.DDTags +import datadog.trace.api.TagMap import datadog.trace.api.config.TracerConfig import datadog.trace.api.naming.v0.NamingSchemaV0 import datadog.trace.api.naming.v1.NamingSchemaV1 @@ -13,10 +14,12 @@ class PeerServiceCalculatorTest extends DDSpecification { setup: def calculator = new PeerServiceCalculator(new NamingSchemaV0().peerService(), Collections.emptyMap()) when: - def enrichedTags = calculator.processTags(tags, null, []) + def unsafeTags = TagMap.fromMap(tags) + calculator.processTags(unsafeTags, null, {link ->}) + then: // tags are not modified - assert enrichedTags == tags + assert unsafeTags == tags where: tags | _ @@ -31,13 +34,16 @@ class PeerServiceCalculatorTest extends DDSpecification { def "schema v1: test peer service default logic and precursors"() { setup: def calculator = new PeerServiceCalculator(new NamingSchemaV1().peerService(), Collections.emptyMap()) + when: tags.put(Tags.SPAN_KIND, Tags.SPAN_KIND_CLIENT) - def calculated = calculator.processTags(tags, null, []) + + def unsafeTags = TagMap.fromMap(tags) + calculator.processTags(unsafeTags, null, {link ->}) then: - calculated.get(DDTags.PEER_SERVICE_SOURCE) == provenance - calculated.get(Tags.PEER_SERVICE) == peerService + unsafeTags.get(DDTags.PEER_SERVICE_SOURCE) == provenance + unsafeTags.get(Tags.PEER_SERVICE) == peerService where: tags | provenance | peerService @@ -55,10 +61,13 @@ class PeerServiceCalculatorTest extends DDSpecification { setup: injectSysConfig(TracerConfig.TRACE_PEER_SERVICE_DEFAULTS_ENABLED, "true") def calculator = new PeerServiceCalculator(new NamingSchemaV0().peerService(), Collections.emptyMap()) + when: - def calculated = calculator.processTags(["span.kind": "client", "peer.hostname": "test"], null, []) + def unsafeTags = TagMap.fromMap(["span.kind": "client", "peer.hostname": "test"]) + calculator.processTags(unsafeTags, null, {link ->}) + then: - assert calculated.get(Tags.PEER_SERVICE) == "test" + assert unsafeTags.get(Tags.PEER_SERVICE) == "test" } @@ -68,9 +77,12 @@ class PeerServiceCalculatorTest extends DDSpecification { when: def tags = ["span.kind": kind, "peer.hostname": "test"] + def unsafeTags = TagMap.fromMap(tags) + + calculator.processTags(unsafeTags, null, {link -> }) then: - assert calculator.processTags(tags, null, []).containsKey(Tags.PEER_SERVICE) == calculate + assert unsafeTags.containsKey(Tags.PEER_SERVICE) == calculate where: kind | calculate @@ -87,11 +99,12 @@ class PeerServiceCalculatorTest extends DDSpecification { def calculator = new PeerServiceCalculator(new NamingSchemaV0().peerService(), Config.get().getPeerServiceMapping()) when: - def calculated = calculator.processTags(tags, null, []) + def unsafeTags = TagMap.fromMap(tags) + calculator.processTags(unsafeTags, null, {link ->}) then: - assert calculated.get(Tags.PEER_SERVICE) == expected - assert calculated.get(DDTags.PEER_SERVICE_REMAPPED_FROM) == original + assert unsafeTags.get(Tags.PEER_SERVICE) == expected + assert unsafeTags.get(DDTags.PEER_SERVICE_REMAPPED_FROM) == original where: tags | expected | original @@ -108,11 +121,12 @@ class PeerServiceCalculatorTest extends DDSpecification { def calculator = new PeerServiceCalculator(new NamingSchemaV0().peerService(), Config.get().getPeerServiceComponentOverrides()) when: - def calculated = calculator.processTags(tags, null, []) + def unsafeTags = TagMap.fromMap(tags) + calculator.processTags(unsafeTags, null, {link -> }) then: - assert calculated.get(Tags.PEER_SERVICE) == expected - assert calculated.get(DDTags.PEER_SERVICE_SOURCE) == source + assert unsafeTags.get(Tags.PEER_SERVICE) == expected + assert unsafeTags.get(DDTags.PEER_SERVICE_SOURCE) == source where: tags | expected | source diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PostProcessorChainTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PostProcessorChainTest.groovy index 8961c8d41f8..3d62f0b29da 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PostProcessorChainTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/PostProcessorChainTest.groovy @@ -1,7 +1,7 @@ package datadog.trace.core.tagprocessor import datadog.trace.api.TagMap -import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink +import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks import datadog.trace.core.DDSpanContext import datadog.trace.test.util.DDSpecification @@ -10,40 +10,43 @@ class PostProcessorChainTest extends DDSpecification { setup: def processor1 = new TagsPostProcessor() { @Override - void processTags(TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + void processTags(TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { unsafeTags.put("key1", "processor1") unsafeTags.put("key2", "processor1") } } def processor2 = new TagsPostProcessor() { @Override - void processTags(TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + void processTags(TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { unsafeTags.put("key1", "processor2") } } def chain = new PostProcessorChain(processor1, processor2) - def tags = TagMap.fromMap(["key1": "root", "key3": "root"]) + + def links = [] + def tags = TagMap.fromMap(["key1": "overwrite", "key3": "unchanged"]) when: - chain.processTags(tags, null, []) + chain.processTags(tags, null, {link -> links.add(link)}) then: - assert tags == ["key1": "processor2", "key2": "processor1", "key3": "root"] + assert tags == ["key1": "processor2", "key2": "processor1", "key3": "unchanged"] + assert links == [] } def "processor can hide tags to next one()"() { setup: def processor1 = new TagsPostProcessor() { @Override - void processTags(TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + void processTags(TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { unsafeTags.clear() unsafeTags.put("my", "tag") } } def processor2 = new TagsPostProcessor() { @Override - void processTags(TagMap unsafeTags, DDSpanContext spanContext, List spanLinks) { + void processTags(TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) { if (unsafeTags.containsKey("test")) { unsafeTags.put("found", "true") } @@ -51,12 +54,15 @@ class PostProcessorChainTest extends DDSpecification { } def chain = new PostProcessorChain(processor1, processor2) + + def links = [] def tags = TagMap.fromMap(["test": "test"]) when: - chain.processTags(tags, null, []) + chain.processTags(tags, null, {link -> links.add(link)}) then: assert tags == ["my": "tag"] + assert links == [] } } diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/QueryObfuscatorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/QueryObfuscatorTest.groovy index 655a1a720fb..1e4332477ed 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/QueryObfuscatorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/QueryObfuscatorTest.groovy @@ -1,6 +1,7 @@ package datadog.trace.core.tagprocessor import datadog.trace.api.DDTags +import datadog.trace.api.TagMap import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.test.util.DDSpecification @@ -14,11 +15,12 @@ class QueryObfuscatorTest extends DDSpecification { ] when: - def result = obfuscator.processTags(tags, null, []) + def unsafeTags = TagMap.fromMap(tags) + obfuscator.processTags(unsafeTags, null, {link ->}) then: - assert result.get(DDTags.HTTP_QUERY) == expectedQuery - assert result.get(Tags.HTTP_URL) == 'http://site.com/index?' + expectedQuery + assert unsafeTags.get(DDTags.HTTP_QUERY) == expectedQuery + assert unsafeTags.get(Tags.HTTP_URL) == 'http://site.com/index?' + expectedQuery where: query | expectedQuery @@ -36,11 +38,12 @@ class QueryObfuscatorTest extends DDSpecification { ] when: - def result = obfuscator.processTags(tags, null, []) + def unsafeTags = TagMap.fromMap(tags) + obfuscator.processTags(unsafeTags, null, {link ->}) then: - assert result.get(DDTags.HTTP_QUERY) == expectedQuery - assert result.get(Tags.HTTP_URL) == 'http://site.com/index?' + expectedQuery + assert unsafeTags.get(DDTags.HTTP_QUERY) == expectedQuery + assert unsafeTags.get(Tags.HTTP_URL) == 'http://site.com/index?' + expectedQuery where: query | expectedQuery diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/SpanPointersProcessorTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/SpanPointersProcessorTest.groovy index 09bae762eff..a3407e30a02 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/SpanPointersProcessorTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/tagprocessor/SpanPointersProcessorTest.groovy @@ -2,6 +2,7 @@ package datadog.trace.core.tagprocessor import datadog.trace.api.DDSpanId import datadog.trace.api.DDTraceId +import datadog.trace.api.TagMap import datadog.trace.bootstrap.instrumentation.api.InstrumentationTags import datadog.trace.bootstrap.instrumentation.api.SpanLink import datadog.trace.core.DDSpanContext @@ -11,22 +12,22 @@ class SpanPointersProcessorTest extends DDSpecification{ def "SpanPointersProcessor adds correct link with basic values"() { given: def processor = new SpanPointersProcessor() - def unsafeTags = [ + def unsafeTags = TagMap.fromMap([ (InstrumentationTags.AWS_BUCKET_NAME): "some-bucket", (InstrumentationTags.AWS_OBJECT_KEY) : "some-key.data", "s3.eTag" : "ab12ef34" - ] + ]) def spanContext = Mock(DDSpanContext) def spanLinks = [] def expectedHash = "e721375466d4116ab551213fdea08413" when: // Process the tags; the processor should remove 's3.eTag' and add one link - def returnedTags = processor.processTags(unsafeTags, spanContext, spanLinks) + processor.processTags(unsafeTags, spanContext, {link -> spanLinks.add(link)}) then: // 1. s3.eTag was removed - !returnedTags.containsKey("s3.eTag") + !unsafeTags.containsKey("s3.eTag") // 2. Exactly one link was added spanLinks.size() == 1 // 3. Check link @@ -43,11 +44,11 @@ class SpanPointersProcessorTest extends DDSpecification{ def "SpanPointersProcessor adds correct link with non-ascii key"() { given: def processor = new SpanPointersProcessor() - def unsafeTags = [ + def unsafeTags = TagMap.fromMap([ (InstrumentationTags.AWS_BUCKET_NAME): "some-bucket", (InstrumentationTags.AWS_OBJECT_KEY) : "some-key.你好", "s3.eTag" : "ab12ef34" - ] + ]) def spanContext = Mock(DDSpanContext) def spanLinks = [] @@ -55,10 +56,10 @@ class SpanPointersProcessorTest extends DDSpecification{ def expectedHash = "d1333a04b9928ab462b5c6cadfa401f4" when: - def returnedTags = processor.processTags(unsafeTags, spanContext, spanLinks) + processor.processTags(unsafeTags, spanContext, {link -> spanLinks.add(link)}) then: - !returnedTags.containsKey("s3.eTag") + !unsafeTags.containsKey("s3.eTag") spanLinks.size() == 1 def link = spanLinks[0] link.traceId() == DDTraceId.ZERO @@ -72,11 +73,11 @@ class SpanPointersProcessorTest extends DDSpecification{ def "SpanPointersProcessor adds correct link with multipart-upload ETag"() { given: def processor = new SpanPointersProcessor() - def unsafeTags = [ + def unsafeTags = TagMap.fromMap([ (InstrumentationTags.AWS_BUCKET_NAME): "some-bucket", (InstrumentationTags.AWS_OBJECT_KEY) : "some-key.data", "s3.eTag" : "ab12ef34-5" - ] + ]) def spanContext = Mock(DDSpanContext) def spanLinks = [] @@ -84,10 +85,10 @@ class SpanPointersProcessorTest extends DDSpecification{ def expectedHash = "2b90dffc37ebc7bc610152c3dc72af9f" when: - def returnedTags = processor.processTags(unsafeTags, spanContext, spanLinks) + processor.processTags(unsafeTags, spanContext, {link -> spanLinks.add(link)}) then: - !returnedTags.containsKey("s3.eTag") + !unsafeTags.containsKey("s3.eTag") spanLinks.size() == 1 def link = spanLinks[0] link.traceId() == DDTraceId.ZERO diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java index af2ccfedc8d..99c90b53b30 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpan.java @@ -18,7 +18,12 @@ import javax.annotation.Nullable; public interface AgentSpan - extends MutableSpan, ImplicitContextKeyed, Context, IGSpanInfo, WithAgentSpan { + extends MutableSpan, + AppendableSpanLinks, + ImplicitContextKeyed, + Context, + IGSpanInfo, + WithAgentSpan { /** * Extracts the span from context. diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AppendableSpanLinks.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AppendableSpanLinks.java new file mode 100644 index 00000000000..f1cc5325695 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AppendableSpanLinks.java @@ -0,0 +1,7 @@ +package datadog.trace.bootstrap.instrumentation.api; + +/** Interface that provides the ability to append a span link */ +@FunctionalInterface +public interface AppendableSpanLinks { + void addLink(AgentSpanLink link); +}