From 934f4008a91c37e07d278191581fd86113780d60 Mon Sep 17 00:00:00 2001 From: Jordan Wong Date: Tue, 4 Feb 2025 14:20:08 -0500 Subject: [PATCH] add draft inferred proxy spans as http request parent --- .../decorator/HttpServerDecorator.java | 385 ++++++++++++++++- .../decorator/HttpServerDecorator.java.rej | 10 + .../trace/api/TracePropagationStyle.java | 2 + .../trace/core/propagation/HttpCodec.java | 1 + .../core/propagation/InferredProxyCodec.java | 391 ++++++++++++++++++ .../trace/core/propagation/W3CHttpCodec.java | 1 + docs/add_new_instrumentation.md | 2 +- .../instrumentation/api/AgentSpanContext.java | 2 + .../instrumentation/api/AgentTracer.java | 4 + .../instrumentation/api/TagContext.java | 5 + 10 files changed, 800 insertions(+), 3 deletions(-) create mode 100644 dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java.rej create mode 100644 dd-trace-core/src/main/java/datadog/trace/core/propagation/InferredProxyCodec.java diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java index 9383c9f1f29..2eb160ce2ad 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java @@ -8,6 +8,8 @@ import datadog.appsec.api.blocking.BlockingException; import datadog.trace.api.Config; import datadog.trace.api.DDTags; +import datadog.trace.api.DDTraceId; +import datadog.trace.api.TraceConfig; import datadog.trace.api.function.TriConsumer; import datadog.trace.api.function.TriFunction; import datadog.trace.api.gateway.BlockResponseFunction; @@ -16,11 +18,13 @@ import datadog.trace.api.gateway.IGSpanInfo; import datadog.trace.api.gateway.RequestContext; import datadog.trace.api.gateway.RequestContextSlot; +import datadog.trace.api.interceptor.MutableSpan; import datadog.trace.api.naming.SpanNaming; import datadog.trace.bootstrap.ActiveSubsystems; import datadog.trace.bootstrap.instrumentation.api.AgentPropagation; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentSpanContext; +import datadog.trace.bootstrap.instrumentation.api.AgentSpanLink; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.ErrorPriorities; import datadog.trace.bootstrap.instrumentation.api.InternalSpanTypes; @@ -47,6 +51,370 @@ public abstract class HttpServerDecorator extends ServerDecorator { + class MySpan implements AgentSpan { + private final AgentSpan apiGatewaySpan; + private final AgentSpan serverSpan; + + MySpan(AgentSpan apiGatewaySpan, AgentSpan serverSpan) { + this.apiGatewaySpan = apiGatewaySpan; + this.serverSpan = serverSpan; + } + + @Override + public DDTraceId getTraceId() { + return serverSpan.getTraceId(); + } + + @Override + public long getSpanId() { + return serverSpan.getSpanId(); + } + + @Override + public AgentSpan setTag(String key, boolean value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setTag(String key, int value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setTag(String key, long value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setTag(String key, double value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setTag(String key, String value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setTag(String key, CharSequence value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setTag(String key, Object value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setTag(String key, Number value) { + return serverSpan.setTag(key, value); + } + + @Override + public AgentSpan setMetric(CharSequence key, int value) { + return serverSpan.setMetric(key, value); + } + + @Override + public AgentSpan setMetric(CharSequence key, long value) { + return serverSpan.setMetric(key, value); + } + + @Override + public AgentSpan setMetric(CharSequence key, double value) { + return serverSpan.setMetric(key, value); + } + + @Override + public AgentSpan setSpanType(CharSequence type) { + return serverSpan.setSpanType(type); + } + + @Override + public Object getTag(String key) { + return serverSpan.getTag(key); + } + + @Override + public AgentSpan setError(boolean error) { + return serverSpan.setError(error); + } + + @Override + public AgentSpan setError(boolean error, byte priority) { + return serverSpan.setError(error, priority); + } + + @Override + public AgentSpan setMeasured(boolean measured) { + return serverSpan.setMeasured(measured); + } + + @Override + public AgentSpan setErrorMessage(String errorMessage) { + return serverSpan.setErrorMessage(errorMessage); + } + + @Override + public AgentSpan addThrowable(Throwable throwable) { + return serverSpan.addThrowable(throwable); + } + + @Override + public AgentSpan addThrowable(Throwable throwable, byte errorPriority) { + return serverSpan.addThrowable(throwable, errorPriority); + } + + @Override + public AgentSpan getLocalRootSpan() { + return serverSpan.getLocalRootSpan(); + } + + @Override + public boolean isSameTrace(AgentSpan otherSpan) { + return serverSpan.isSameTrace(otherSpan); + } + + @Override + public AgentSpanContext context() { + return serverSpan.context(); + } + + @Override + public String getBaggageItem(String key) { + return serverSpan.getBaggageItem(key); + } + + @Override + public AgentSpan setBaggageItem(String key, String value) { + return serverSpan.setBaggageItem(key, value); + } + + @Override + public AgentSpan setHttpStatusCode(int statusCode) { + return serverSpan.setHttpStatusCode(statusCode); + } + + @Override + public short getHttpStatusCode() { + return serverSpan.getHttpStatusCode(); + } + + @Override + public void finish() { + serverSpan.finish(); + if (apiGatewaySpan != null) { + apiGatewaySpan.finish(); + } + } + + @Override + public void finish(long finishMicros) { + serverSpan.finish(finishMicros); + if (apiGatewaySpan != null) { + apiGatewaySpan.finish(finishMicros); + } + } + + @Override + public void finishWithDuration(long durationNanos) { + serverSpan.finishWithDuration(durationNanos); + if (apiGatewaySpan != null) { + apiGatewaySpan.finishWithDuration(durationNanos); + } + } + + @Override + public void beginEndToEnd() { + serverSpan.beginEndToEnd(); + } + + @Override + public void finishWithEndToEnd() { + serverSpan.finishWithEndToEnd(); + if (apiGatewaySpan != null) { + apiGatewaySpan.finishWithEndToEnd(); + } + } + + @Override + public boolean phasedFinish() { + final boolean ret = serverSpan.phasedFinish(); + if (apiGatewaySpan != null) { + apiGatewaySpan.phasedFinish(); + } + return ret; + } + + @Override + public void publish() { + serverSpan.publish(); + } + + @Override + public CharSequence getSpanName() { + return serverSpan.getSpanName(); + } + + @Override + public void setSpanName(CharSequence spanName) { + serverSpan.setSpanName(spanName); + } + + @Deprecated + @Override + public boolean hasResourceName() { + return serverSpan.hasResourceName(); + } + + @Override + public byte getResourceNamePriority() { + return serverSpan.getResourceNamePriority(); + } + + @Override + public AgentSpan setResourceName(CharSequence resourceName) { + return serverSpan.setResourceName(resourceName); + } + + @Override + public AgentSpan setResourceName(CharSequence resourceName, byte priority) { + return serverSpan.setResourceName(resourceName, priority); + } + + @Override + public boolean eligibleForDropping() { + return serverSpan.eligibleForDropping(); + } + + @Override + public RequestContext getRequestContext() { + return serverSpan.getRequestContext(); + } + + @Override + public Integer forceSamplingDecision() { + return serverSpan.forceSamplingDecision(); + } + + @Override + public AgentSpan setSamplingPriority(int newPriority, int samplingMechanism) { + return serverSpan.setSamplingPriority(newPriority, samplingMechanism); + } + + @Override + public TraceConfig traceConfig() { + return serverSpan.traceConfig(); + } + + @Override + public void addLink(AgentSpanLink link) { + serverSpan.addLink(link); + } + + @Override + public AgentSpan setMetaStruct(String field, Object value) { + return serverSpan.setMetaStruct(field, value); + } + + @Override + public boolean isOutbound() { + return serverSpan.isOutbound(); + } + + @Override + public AgentSpan asAgentSpan() { + return serverSpan.asAgentSpan(); + } + + @Override + public long getStartTime() { + return serverSpan.getStartTime(); + } + + @Override + public long getDurationNano() { + return serverSpan.getDurationNano(); + } + + @Override + public CharSequence getOperationName() { + return serverSpan.getOperationName(); + } + + @Override + public MutableSpan setOperationName(CharSequence serviceName) { + return serverSpan.setOperationName(serviceName); + } + + @Override + public String getServiceName() { + return serverSpan.getServiceName(); + } + + @Override + public MutableSpan setServiceName(String serviceName) { + return serverSpan.setServiceName(serviceName); + } + + @Override + public CharSequence getResourceName() { + return serverSpan.getResourceName(); + } + + @Override + public Integer getSamplingPriority() { + return serverSpan.getSamplingPriority(); + } + + @Deprecated + @Override + public MutableSpan setSamplingPriority(int newPriority) { + return serverSpan.setSamplingPriority(newPriority); + } + + @Override + public String getSpanType() { + return serverSpan.getSpanType(); + } + + @Override + public Map getTags() { + return serverSpan.getTags(); + } + + @Override + public boolean isError() { + return serverSpan.isError(); + } + + @Deprecated + @Override + public MutableSpan getRootSpan() { + return serverSpan.getRootSpan(); + } + + @Override + public void setRequestBlockingAction(Flow.Action.RequestBlockingAction rba) { + serverSpan.setRequestBlockingAction(rba); + } + + @Override + public Flow.Action.RequestBlockingAction getRequestBlockingAction() { + return serverSpan.getRequestBlockingAction(); + } + + @Override + public boolean isRequiresPostProcessing() { + return serverSpan.isRequiresPostProcessing(); + } + + @Override + public void setRequiresPostProcessing(boolean requiresPostProcessing) { + serverSpan.setRequiresPostProcessing(requiresPostProcessing); + } + } + private static final Logger log = LoggerFactory.getLogger(HttpServerDecorator.class); private static final int UNSET_PORT = 0; @@ -138,9 +506,20 @@ public AgentSpan startSpan(REQUEST_CARRIER carrier, AgentSpanContext.Extracted c public AgentSpan startSpan( String instrumentationName, REQUEST_CARRIER carrier, AgentSpanContext.Extracted context) { + AgentSpan apiGtwSpan = null; + if (context.isApiGatewaySupported()) { + // create the apigtw span + apiGtwSpan = + tracer() + .startSpan( + "api_gtw_instrumentation_name", "test apigw span", callIGCallbackStart(context)); + } AgentSpan span = tracer() - .startSpan(instrumentationName, spanName(), callIGCallbackStart(context)) + .startSpan( + instrumentationName, + spanName(), + apiGtwSpan != null ? apiGtwSpan.context() : callIGCallbackStart(context)) .setMeasured(true); Flow flow = callIGCallbackRequestHeaders(span, carrier); if (flow.getAction() instanceof Flow.Action.RequestBlockingAction) { @@ -150,7 +529,9 @@ public AgentSpan startSpan( if (null != carrier && null != getter) { tracer().getDataStreamsMonitoring().setCheckpoint(span, SERVER_PATHWAY_EDGE_TAGS, 0, 0); } - return span; + System.out.println("starting http server span"); + span.setTag("apigw-testing", "hello jordan regular http span"); + return new MySpan(apiGtwSpan, span); } public AgentSpan onRequest( diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java.rej b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java.rej new file mode 100644 index 00000000000..34532ff0ad6 --- /dev/null +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java.rej @@ -0,0 +1,10 @@ +diff a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/decorator/HttpServerDecorator.java (rejected hunks) +@@ -150,7 +523,7 @@ public abstract class HttpServerDecorator void inject( + // final DDSpanContext context, final C carrier, final AgentPropagation.Setter setter); + // } + // + // /** This interface defines propagated context extractor. */ + // public interface Extractor { + // /** + // * Extracts a propagated context from the given carrier using the provided getter. + // * + // * @param carrier The carrier containing the propagated context. + // * @param getter The getter used to extract data from the carrier. + // * @param The type of the carrier. + // * @return {@code null} for failed context extraction, a {@link TagContext} instance for + // partial + // * context extraction or an {@link ExtractedContext} for complete context extraction. + // */ + // TagContext extract(final C carrier, final AgentPropagation.ContextVisitor getter); + // + // /** + // * Cleans up any thread local resources associated with this extractor. + // * + // *

Implementations should override this method if they need to clean up any resources. + // * + // *

Currently only used from tests. + // */ + // default void cleanup() {} + // } + // + // public static Injector createInjector( + // Config config, + // Set styles, + // Map invertedBaggageMapping) { + // ArrayList injectors = + // new ArrayList<>(createInjectors(config, styles, invertedBaggageMapping).values()); + // return new CompoundInjector(injectors); + // } + // + // public static Map allInjectorsFor( + // Config config, Map reverseBaggageMapping) { + // return createInjectors( + // config, EnumSet.allOf(TracePropagationStyle.class), reverseBaggageMapping); + // } + // + // private static Map createInjectors( + // Config config, + // Set propagationStyles, + // Map reverseBaggageMapping) { + // EnumMap result = new + // EnumMap<>(TracePropagationStyle.class); + // for (TracePropagationStyle style : propagationStyles) { + // switch (style) { + // case DATADOG: + // result.put(style, DatadogHttpCodec.newInjector(reverseBaggageMapping)); + // break; + // case B3SINGLE: + // result.put( + // style, + // B3HttpCodec.newSingleInjector(config.isTracePropagationStyleB3PaddingEnabled())); + // break; + // case B3MULTI: + // result.put( + // style, + // B3HttpCodec.newMultiInjector(config.isTracePropagationStyleB3PaddingEnabled())); + // break; + // case HAYSTACK: + // result.put(style, HaystackHttpCodec.newInjector(reverseBaggageMapping)); + // break; + // case XRAY: + // result.put(style, XRayHttpCodec.newInjector(reverseBaggageMapping)); + // break; + // case NONE: + // result.put(style, NoneCodec.INJECTOR); + // break; + // case TRACECONTEXT: + // result.put(style, W3CHttpCodec.newInjector(reverseBaggageMapping)); + // break; + // default: + // log.debug("No implementation found to inject propagation style: {}", style); + // break; + // } + // } + // return result; + // } + // + // public static Extractor createExtractor( + // Config config, Supplier traceConfigSupplier) { + // final List extractors = new ArrayList<>(); + // for (final TracePropagationStyle style : config.getTracePropagationStylesToExtract()) { + // switch (style) { + // case DATADOG: + // extractors.add(DatadogHttpCodec.newExtractor(config, traceConfigSupplier)); + // break; + // case B3SINGLE: + // extractors.add(B3HttpCodec.newSingleExtractor(config, traceConfigSupplier)); + // break; + // case B3MULTI: + // extractors.add(B3HttpCodec.newMultiExtractor(config, traceConfigSupplier)); + // break; + // case HAYSTACK: + // extractors.add(HaystackHttpCodec.newExtractor(config, traceConfigSupplier)); + // break; + // case XRAY: + // extractors.add(XRayHttpCodec.newExtractor(config, traceConfigSupplier)); + // break; + // case NONE: + // extractors.add(NoneCodec.newExtractor(config, traceConfigSupplier)); + // break; + // case TRACECONTEXT: + // extractors.add(W3CHttpCodec.newExtractor(config, traceConfigSupplier)); + // break; + // // TODO: make case INFERREDPROXYSPAN + // default: + // log.debug("No implementation found to extract propagation style: {}", style); + // break; + // } + // } + // switch (extractors.size()) { + // case 0: + // return StubExtractor.INSTANCE; + // case 1: + // return extractors.get(0); + // default: + // return new CompoundExtractor(extractors, config.isTracePropagationExtractFirst()); + // } + // } + // + // public static class CompoundInjector implements Injector { + // + // private final List injectors; + // + // public CompoundInjector(final List injectors) { + // this.injectors = injectors; + // } + // + // @Override + // public void inject( + // final DDSpanContext context, final C carrier, final AgentPropagation.Setter setter) { + // log.debug("Inject context {}", context); + // for (final Injector injector : injectors) { + // injector.inject(context, carrier, setter); + // } + // } + // } + // + // private static class StubExtractor implements Extractor { + // private static final StubExtractor INSTANCE = new StubExtractor(); + // + // @Override + // public TagContext extract(C carrier, AgentPropagation.ContextVisitor getter) { + // return null; + // } + // } + // + // public static class CompoundExtractor implements Extractor { + // private final List extractors; + // private final boolean extractFirst; + // + // public CompoundExtractor(final List extractors, boolean extractFirst) { + // this.extractors = extractors; + // this.extractFirst = extractFirst; + // } + // + // @Override + // public TagContext extract( + // final C carrier, final AgentPropagation.ContextVisitor getter) { + // ExtractedContext context = null; + // TagContext partialContext = null; + // // Extract and cache all headers in advance + // ExtractionCache extractionCache = new ExtractionCache<>(carrier, getter); + // + // for (final Extractor extractor : this.extractors) { + // TagContext extracted = extractor.extract(extractionCache, extractionCache); + // // Check if context is valid + // if (extracted instanceof ExtractedContext) { + // ExtractedContext extractedContext = (ExtractedContext) extracted; + // // If no prior valid context, store it as first valid context + // if (context == null) { + // context = extractedContext; + // // Stop extraction if only extracting first valid context and drop everything else + // if (this.extractFirst) { + // break; + // } + // } + // // If another valid context is extracted + // else { + // if (traceIdMatch(context.getTraceId(), extractedContext.getTraceId())) { + // boolean comingFromTraceContext = extracted.getPropagationStyle() == TRACECONTEXT; + // if (comingFromTraceContext) { + // applyTraceContextToFirstContext(context, extractedContext, extractionCache); + // } + // } else { + // // Terminate extracted context and add it as span link + // context.addTerminatedContextLink( + // DDSpanLink.from( + // (ExtractedContext) extracted, + // SpanAttributes.builder() + // .put("reason", "terminated_context") + // .put("context_headers", extracted.getPropagationStyle().toString()) + // .build())); + // // TODO Note: Other vendor tracestate will be lost here + // } + // } + // } + // // Check if context is at least partial to keep it as first valid partial context found + // else if (extracted != null && partialContext == null) { + // partialContext = extracted; + // } + // } + // + // if (context != null) { + // log.debug("Extract complete context {}", context); + // return context; + // } else if (partialContext != null) { + // log.debug("Extract incomplete context {}", partialContext); + // return partialContext; + // } else { + // log.debug("Extract no context"); + // return null; + // } + // } + // + // /** + // * Applies span ID from W3C trace context over any other valid context previously found. + // * + // * @param firstContext The first valid context found. + // * @param traceContext The trace context to apply. + // * @param extractionCache The extraction cache to get quick access to any extra information. + // * @param The carrier type. + // */ + // private void applyTraceContextToFirstContext( + // ExtractedContext firstContext, + // ExtractedContext traceContext, + // ExtractionCache extractionCache) { + // // Propagate newly extracted W3C tracestate to first valid context + // String extractedTracestate = traceContext.getPropagationTags().getW3CTracestate(); + // firstContext.getPropagationTags().updateW3CTracestate(extractedTracestate); + // // Check if parent spans differ to reconcile them + // if (firstContext.getSpanId() != traceContext.getSpanId()) { + // // Override parent span id with W3C one + // firstContext.overrideSpanId(traceContext.getSpanId()); + // // Add last parent ID as a span tag (check W3C first, else Datadog) + // CharSequence lastParentId = traceContext.getPropagationTags().getLastParentId(); + // if (lastParentId == null) { + // lastParentId = extractionCache.getDatadogSpanIdHex(); + // } + // if (lastParentId != null) { + // firstContext.putTag(PARENT_ID, lastParentId.toString()); + // } + // } + // } + // } + // + // private static class ExtractionCache + // implements AgentPropagation.KeyClassifier, + // AgentPropagation.ContextVisitor> { + // /** Cached context key-values (even indexes are header names, odd indexes are header + // values). */ + // private final List keysAndValues; + // /** + // * The parent span identifier from {@link DatadogHttpCodec#SPAN_ID_KEY} header formatted as + // 16 + // * hexadecimal characters, {@code null} if absent or invalid. + // */ + // private String datadogSpanIdHex; + // + // public ExtractionCache(C carrier, AgentPropagation.ContextVisitor getter) { + // this.keysAndValues = new ArrayList<>(32); + // getter.forEachKey(carrier, this); + // } + // + // @Override + // public boolean accept(String key, String value) { + // this.keysAndValues.add(key); + // this.keysAndValues.add(value); + // cacheDatadogSpanId(key, value); + // return true; + // } + // + // private void cacheDatadogSpanId(String key, String value) { + // if (SPAN_ID_KEY.equalsIgnoreCase(key)) { + // try { + // // Parse numeric header value to format it as 16 hexadecimal character format + // this.datadogSpanIdHex = DDSpanId.toHexStringPadded(DDSpanId.from(value)); + // } catch (NumberFormatException ignored) { + // } + // } + // } + // + // private String getDatadogSpanIdHex() { + // return this.datadogSpanIdHex; + // } + // + // @Override + // public void forEachKey(ExtractionCache carrier, AgentPropagation.KeyClassifier + // classifier) { + // List keysAndValues = carrier.keysAndValues; + // for (int i = 0; i < keysAndValues.size(); i += 2) { + // classifier.accept(keysAndValues.get(i), keysAndValues.get(i + 1)); + // } + // } + // } + // + // /** + // * Checks if trace identifier matches, even if they are not encoded using the same size + // (64-bit vs + // * 128-bit). + // * + // * @param a A trace identifier to check. + // * @param b Another trace identifier to check. + // * @return {@code true} if the trace identifiers matches, {@code false} otherwise. + // */ + // private static boolean traceIdMatch(DDTraceId a, DDTraceId b) { + // if (a instanceof DD128bTraceId && b instanceof DD128bTraceId + // || a instanceof DD64bTraceId && b instanceof DD64bTraceId) { + // return a.equals(b); + // } else { + // return a.toLong() == b.toLong(); + // } + // } + // + // /** URL encode value */ + // static String encode(final String value) { + // String encoded = value; + // try { + // encoded = URLEncoder.encode(value, "UTF-8"); + // } catch (final UnsupportedEncodingException e) { + // log.debug("Failed to encode value - {}", value); + // } + // return encoded; + // } + // + // /** + // * Encodes baggage value according W3C RFC. + // * + // * @param value The baggage value. + // * @return The encoded baggage value. + // */ + // static String encodeBaggage(final String value) { + // // Fix encoding to comply with https://www.w3.org/TR/baggage/#value and use percent-encoding + // // (RFC3986) + // // for space ( ) instead of plus (+) from 'application/x-www-form' MIME encoding + // return encode(value).replace("+", "%20"); + // } + // + // /** URL decode value */ + // static String decode(final String value) { + // String decoded = value; + // try { + // decoded = URLDecoder.decode(value, "UTF-8"); + // } catch (final UnsupportedEncodingException | IllegalArgumentException e) { + // log.debug("Failed to decode value - {}", value); + // } + // return decoded; + // } + // + // static String firstHeaderValue(final String value) { + // if (value == null) { + // return null; + // } + // + // int firstComma = value.indexOf(','); + // return firstComma == -1 ? value : value.substring(0, firstComma).trim(); + // } +} diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java index 4ae2fc4efee..e9e9ce29aef 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/W3CHttpCodec.java @@ -198,6 +198,7 @@ public boolean accept(String key, String value) { if (null != value) { switch (classification) { case TRACE_PARENT: + // look here store trace parent return storeTraceParent(value); case TRACE_STATE: return storeTraceState(value); diff --git a/docs/add_new_instrumentation.md b/docs/add_new_instrumentation.md index 7a2bcac05b1..bf6465ab2d2 100644 --- a/docs/add_new_instrumentation.md +++ b/docs/add_new_instrumentation.md @@ -131,7 +131,7 @@ public class HeadersInjectAdapter { to reduce code duplication. Confining extensive tag manipulation to the Decorators also makes the Advice class easier to understand and maintain. -```java +```java import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpResponse; diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpanContext.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpanContext.java index 1f10c1ed24b..c1288b5fe83 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpanContext.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentSpanContext.java @@ -88,5 +88,7 @@ interface Extracted extends AgentSpanContext { String getTrueClientIp(); String getCustomIpHeader(); + + boolean isApiGatewaySupported(); } } diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java index 9fb97ae2c74..156567f1e2f 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java @@ -1111,6 +1111,10 @@ public String getTrueClientIp() { public String getCustomIpHeader() { return null; } + + public boolean isApiGatewaySupported() { + return true; + } } public static class NoopAgentTraceCollector implements AgentTraceCollector { diff --git a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/TagContext.java b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/TagContext.java index fdf9580cbb9..795860e310f 100644 --- a/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/TagContext.java +++ b/internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/TagContext.java @@ -163,6 +163,11 @@ public String getCustomIpHeader() { return httpHeaders.customIpHeader; } + @Override + public boolean isApiGatewaySupported() { + return true; + } + public final Map getTags() { return tags; }