Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import datadog.trace.api.KnownTagCodec;
import datadog.trace.api.KnownTags;
import datadog.trace.api.ProcessTags;
import datadog.trace.api.SpanStorage;
import datadog.trace.api.TagMap;
import datadog.trace.api.cache.DDCache;
import datadog.trace.api.cache.DDCaches;
Expand Down Expand Up @@ -68,7 +69,7 @@
* the associated Span instance
*/
public class DDSpanContext
implements AgentSpanContext, RequestContext, TraceSegment, ProfilerContext {
implements AgentSpanContext, RequestContext, TraceSegment, ProfilerContext, SpanStorage {
private static final Logger log = LoggerFactory.getLogger(DDSpanContext.class);

public static final String PRIORITY_SAMPLING_KEY = "_sampling_priority_v1";
Expand Down Expand Up @@ -1395,6 +1396,31 @@ Object getTag(final String key) {
}
}

/*
* SpanStorage: the span's tags, loaded and stored with no interception.
* Unsynchronized, like unsafeGetTag: callers hold the span's tag lock, as post-processing does.
*/

@Override
public Object load(String tag) {
return unsafeTags.getObject(tag);
}

@Override
public String loadString(String tag) {
return unsafeTags.getString(tag);
}

@Override
public void store(String tag, Object value) {
unsafeTags.set(tag, value);
}

@Override
public void store(TagMap.EntryReader entry) {
unsafeTags.set(entry);
}

/**
* This is not thread-safe and must only be used when it can be guaranteed that the context will
* not be mutated. This is internal API and must not be exposed to users.
Expand Down Expand Up @@ -1500,7 +1526,7 @@ public <T> void setMetaStruct(final String field, final T value) {

void earlyProcessTags(AppendableSpanLinks links) {
synchronized (unsafeTags) {
TagsPostProcessorFactory.eagerProcessor().processTags(unsafeTags, this, links);
TagsPostProcessorFactory.eagerProcessor().processTags(this, this, links);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package datadog.trace.core.tagprocessor;

import datadog.trace.api.SpanStorage;
import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks;
import datadog.trace.core.DDSpanContext;
import java.util.Objects;
import javax.annotation.Nonnull;

/** Runs eager post-processors in order. */
public final class EagerPostProcessorChain extends EagerTagsPostProcessor {
private final EagerTagsPostProcessor[] chain;

public EagerPostProcessorChain(@Nonnull final EagerTagsPostProcessor... processors) {
chain = Objects.requireNonNull(processors);
}

@Override
public void processTags(
SpanStorage storage, DDSpanContext spanContext, AppendableSpanLinks spanLinks) {
for (final EagerTagsPostProcessor processor : chain) {
processor.processTags(storage, spanContext, spanLinks);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package datadog.trace.core.tagprocessor;

import datadog.trace.api.SpanStorage;
import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks;
import datadog.trace.core.DDSpanContext;

/**
* A tag post-processor run on the application thread as a span finishes. It works on the span's
* {@link SpanStorage} rather than a {@code TagMap}, so the span needn't build one for it.
*/
public abstract class EagerTagsPostProcessor {
/**
* Processes the span's tags.
*
* @param contents the span's contents to read and write; the caller holds the span's tag lock
* @param spanContext the span, for its other properties
* @param spanLinks the span's links
*/
public abstract void processTags(
SpanStorage storage, DDSpanContext spanContext, AppendableSpanLinks spanLinks);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import static datadog.trace.bootstrap.instrumentation.api.Tags.HTTP_ROUTE;
import static datadog.trace.bootstrap.instrumentation.api.Tags.HTTP_URL;

import datadog.trace.api.TagMap;
import datadog.trace.api.SpanStorage;
import datadog.trace.api.endpoint.EndpointResolver;
import datadog.trace.api.internal.VisibleForTesting;
import datadog.trace.bootstrap.instrumentation.api.AppendableSpanLinks;
Expand All @@ -30,7 +30,7 @@
* <li>If {@code alwaysSimplifiedEndpoint=true}, always compute from URL regardless of route
* </ul>
*/
public class HttpEndpointPostProcessor extends TagsPostProcessor {
public class HttpEndpointPostProcessor extends EagerTagsPostProcessor {
private static final Logger log = LoggerFactory.getLogger(HttpEndpointPostProcessor.class);

private final EndpointResolver endpointResolver;
Expand All @@ -55,19 +55,19 @@ public HttpEndpointPostProcessor() {

@Override
public void processTags(
TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) {
SpanStorage unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) {
if (!endpointResolver.isEnabled()) {
log.debug("EndpointResolver is not enabled, skipping HTTP endpoint post processing");
return;
}

if (unsafeTags.getObject(HTTP_METHOD) == null) {
if (unsafeTags.load(HTTP_METHOD) == null) {
return;
}

try {
String httpRoute = unsafeTags.getString(HTTP_ROUTE);
String httpUrl = unsafeTags.getString(HTTP_URL);
String httpRoute = unsafeTags.loadString(HTTP_ROUTE);
String httpUrl = unsafeTags.loadString(HTTP_URL);
endpointResolver.resolveEndpoint(unsafeTags, httpRoute, httpUrl);
} catch (Throwable t) {
log.debug("Error processing HTTP endpoint for span {}", spanContext.getSpanId(), t);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import static datadog.trace.bootstrap.instrumentation.api.Tags.VERSION;

import datadog.trace.api.DDTags;
import datadog.trace.api.SpanStorage;
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 javax.annotation.Nonnull;
import javax.annotation.Nullable;

public final class InternalTagsAdder extends TagsPostProcessor {
public final class InternalTagsAdder extends EagerTagsPostProcessor {
private final UTF8BytesString ddService;

// Prebuilt once to avoid per-span Entry allocation.
Expand All @@ -28,21 +29,21 @@ public InternalTagsAdder(@Nonnull final String ddService, @Nullable final String

@Override
public void processTags(
TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) {
SpanStorage unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) {
if (spanContext == null) {
return;
}

if (!ddService.toString().equalsIgnoreCase(spanContext.getServiceName())) {
if (baseServiceEntry != null) {
// service name != DD_SERVICE
unsafeTags.set(baseServiceEntry);
unsafeTags.store(baseServiceEntry);
}
} else {
// as per config consistency, the version tag is added across tracers only if
// the service name is DD_SERVICE and version tag is not manually set
if (versionEntry != null && !unsafeTags.containsKey(VERSION)) {
unsafeTags.set(versionEntry);
if (versionEntry != null && unsafeTags.load(VERSION) == null) {
unsafeTags.store(versionEntry);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import datadog.trace.api.Config;
import datadog.trace.api.DDTags;
import datadog.trace.api.TagMap;
import datadog.trace.api.SpanStorage;
import datadog.trace.api.internal.VisibleForTesting;
import datadog.trace.api.naming.NamingSchema;
import datadog.trace.api.naming.SpanNaming;
Expand All @@ -12,7 +12,7 @@
import java.util.Map;
import javax.annotation.Nonnull;

public final class PeerServiceCalculator extends TagsPostProcessor {
public final class PeerServiceCalculator extends EagerTagsPostProcessor {
private final NamingSchema.ForPeerService peerServiceNaming;

private final Map<String, String> peerServiceMapping;
Expand All @@ -34,8 +34,8 @@ public PeerServiceCalculator() {

@Override
public void processTags(
TagMap unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) {
Object peerService = unsafeTags.getObject(Tags.PEER_SERVICE);
SpanStorage unsafeTags, DDSpanContext spanContext, AppendableSpanLinks spanLinks) {
Object peerService = unsafeTags.load(Tags.PEER_SERVICE);
// the user set it
if (peerService != null) {
if (canRemap) {
Expand All @@ -46,18 +46,18 @@ public void processTags(
// calculate the defaults (if any)
peerServiceNaming.tags(unsafeTags);
// only remap if the mapping is not empty (saves one get)
remapPeerService(unsafeTags, canRemap ? unsafeTags.getObject(Tags.PEER_SERVICE) : null);
remapPeerService(unsafeTags, canRemap ? unsafeTags.load(Tags.PEER_SERVICE) : null);
return;
}
// we have no peer.service and we do not compute defaults. Leave the map untouched
}

private void remapPeerService(TagMap unsafeTags, Object value) {
private void remapPeerService(SpanStorage unsafeTags, Object value) {
if (value != null) {
String mapped = peerServiceMapping.get(value);
if (mapped != null) {
unsafeTags.put(Tags.PEER_SERVICE, mapped);
unsafeTags.put(DDTags.PEER_SERVICE_REMAPPED_FROM, value);
unsafeTags.store(Tags.PEER_SERVICE, mapped);
unsafeTags.store(DDTags.PEER_SERVICE_REMAPPED_FROM, value);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ public final class TagsPostProcessorFactory {
private static boolean addRemoteHostname = true;

private static class Lazy {
private static TagsPostProcessor eagerProcessor = createEagerChain();
private static EagerTagsPostProcessor eagerProcessor = createEagerChain();
private static TagsPostProcessor lazyProcessor = createLazyChain();

private static TagsPostProcessor createEagerChain() {
final List<TagsPostProcessor> processors = new ArrayList<>(3);
private static EagerTagsPostProcessor createEagerChain() {
final List<EagerTagsPostProcessor> processors = new ArrayList<>(3);
processors.add(new PeerServiceCalculator());
if (addInternalTags) {
processors.add(
Expand All @@ -24,7 +24,7 @@ private static TagsPostProcessor createEagerChain() {
if (Config.get().isTraceResourceRenamingEnabled()) {
processors.add(new HttpEndpointPostProcessor());
}
return new PostProcessorChain(processors.toArray(new TagsPostProcessor[0]));
return new EagerPostProcessorChain(processors.toArray(new EagerTagsPostProcessor[0]));
}

private static TagsPostProcessor createLazyChain() {
Expand Down Expand Up @@ -54,7 +54,7 @@ private static TagsPostProcessor createLazyChain() {
}
}

public static TagsPostProcessor eagerProcessor() {
public static EagerTagsPostProcessor eagerProcessor() {
return Lazy.eagerProcessor;
}

Expand Down
27 changes: 27 additions & 0 deletions internal-api/src/main/java/datadog/trace/api/SpanStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package datadog.trace.api;

/**
* A span's tags as stored, for the tracer core's processing pipeline: loads and stores go straight
* to storage, with no interception. Thread safety is up to the implementation; {@code
* DDSpanContext}'s expects the span's tag lock to be held.
*
* <p>Its own verbs, {@code load} and {@code store}, keep it apart from {@link TagMap}'s {@code
* get}/{@code set} and the span's intercepted {@code getTag}/{@code setTag}, so a type can offer
* several of these without a clash.
*
* <p>This is the first slice: only what the eager tag post-processors need. Id variants, typed
* loads and primitive stores come as more of the pipeline moves to it.
*/
public interface SpanStorage {
/** The tag's value, or null when it's absent. */
Object load(String tag);

/** The tag's value as a string, or null when it's absent. */
String loadString(String tag);

/** Stores the tag; a null value removes it. */
void store(String tag, Object value);

/** Stores the entry's tag; a null entry is a no-op. */
void store(TagMap.EntryReader entry);
}
25 changes: 24 additions & 1 deletion internal-api/src/main/java/datadog/trace/api/TagMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
* <li>adaptive collision
* </ul>
*/
public final class TagMap implements Map<String, Object>, Iterable<TagMap.EntryReader> {
public final class TagMap
implements Map<String, Object>, Iterable<TagMap.EntryReader>, SpanStorage {
/** Immutable empty TagMap - similar to {@link Collections#emptyMap()} */
// Frozen view over a length-1 array: bucket masking needs a power-of-two array length (size 0
// would fail with ArrayIndexOutOfBoundsException, size 1 works), and the private constructor
Expand Down Expand Up @@ -1346,6 +1347,28 @@ public String getString(String tag) {
return entry == null ? null : entry.stringValue();
}

/* SpanStorage, for standalone maps handed to the pipeline: TagMap's own get and set. */

@Override
public Object load(String tag) {
return this.getObject(tag);
}

@Override
public String loadString(String tag) {
return this.getString(tag);
}

@Override
public void store(String tag, Object value) {
this.set(tag, value);
}

@Override
public void store(EntryReader entry) {
this.set(entry);
}

public boolean getBoolean(String tag) {
return this.getBooleanOrDefault(tag, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static datadog.trace.bootstrap.instrumentation.api.Tags.HTTP_ENDPOINT;

import datadog.trace.api.SpanStorage;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -50,9 +51,7 @@ public EndpointResolver(boolean enabled, boolean alwaysSimplifiedEndpoint) {
*/
@Nullable
public String resolveEndpoint(
java.util.Map<String, Object> unsafeTags,
@Nullable String httpRoute,
@Nullable String httpUrl) {
SpanStorage unsafeTags, @Nullable String httpRoute, @Nullable String httpUrl) {
if (!enabled) {
return null;
}
Expand All @@ -61,7 +60,7 @@ public String resolveEndpoint(
if (alwaysSimplifiedEndpoint) {
String endpoint = computeEndpoint(httpUrl);
if (endpoint != null) {
unsafeTags.put(HTTP_ENDPOINT, endpoint);
unsafeTags.store(HTTP_ENDPOINT, endpoint);
}
return endpoint;
}
Expand All @@ -74,7 +73,7 @@ public String resolveEndpoint(
// Compute endpoint from URL and tag the span
String endpoint = computeEndpoint(httpUrl);
if (endpoint != null) {
unsafeTags.put(HTTP_ENDPOINT, endpoint);
unsafeTags.store(HTTP_ENDPOINT, endpoint);
}
return endpoint;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package datadog.trace.api.naming;

import datadog.trace.api.TagMap;
import datadog.trace.api.SpanStorage;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -232,7 +232,7 @@ interface ForPeerService {
* @param unsafeTags the span tags. Map to be mutated
*/
@Nonnull
void tags(@Nonnull TagMap unsafeTags);
void tags(@Nonnull SpanStorage unsafeTags);
}

interface ForServer {
Expand Down
Loading
Loading