From 37ad082f0a3f7c976106ff330e4426affbcc373d Mon Sep 17 00:00:00 2001 From: Bruce Bujon Date: Mon, 12 May 2025 11:26:35 +0200 Subject: [PATCH 1/2] feat(gateway): Fix inferred gateway span design Move their context and propagator into tracing/api. Refactor tests Simplify context element Fix propagator --- .../datadog/context/InferredProxyContext.java | 50 -- .../propagation/InferredProxyPropagator.java | 74 --- .../context/InferredProxyHandlingTest.java | 465 ------------------ .../decorator/HttpServerDecorator.java | 25 +- .../java/datadog/trace/core/CoreTracer.java | 2 +- .../inferredproxy/InferredProxyHeaders.java | 40 ++ .../InferredProxyPropagator.java | 48 ++ .../InferredProxyHeadersTests.java | 60 +++ .../InferredProxyPropagatorTests.java | 203 ++++++++ 9 files changed, 364 insertions(+), 603 deletions(-) delete mode 100644 components/context/src/main/java/datadog/context/InferredProxyContext.java delete mode 100644 components/context/src/main/java/datadog/context/propagation/InferredProxyPropagator.java delete mode 100644 components/context/src/test/java/datadog/context/InferredProxyHandlingTest.java create mode 100644 internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeaders.java create mode 100644 internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagator.java create mode 100644 internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java create mode 100644 internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagatorTests.java diff --git a/components/context/src/main/java/datadog/context/InferredProxyContext.java b/components/context/src/main/java/datadog/context/InferredProxyContext.java deleted file mode 100644 index 51eecc4cc02..00000000000 --- a/components/context/src/main/java/datadog/context/InferredProxyContext.java +++ /dev/null @@ -1,50 +0,0 @@ -package datadog.context; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class InferredProxyContext implements ImplicitContextKeyed { - public static final ContextKey CONTEXT_KEY = - ContextKey.named("inferred-proxy-key"); - private final Map inferredProxy; - - public static InferredProxyContext fromContext(Context context) { - return context.get(CONTEXT_KEY); - } - - public InferredProxyContext(Map contextInfo) { - this.inferredProxy = - (contextInfo == null || contextInfo.isEmpty()) - ? new HashMap<>() - : new HashMap<>(contextInfo); - } - - public InferredProxyContext() { - this.inferredProxy = new HashMap<>(); - } - - public Map getInferredProxyContext() { - return Collections.unmodifiableMap(inferredProxy); - } - - public void putInferredProxyInfo(String key, String value) { - inferredProxy.put(key, value); - } - - public void removeInferredProxyInfo(String key) { - inferredProxy.remove(key); - } - - /** - * Creates a new context with this value under its chosen key. - * - * @param context the context to copy the original values from. - * @return the new context with the implicitly keyed value. - * @see Context#with(ImplicitContextKeyed) - */ - @Override - public Context storeInto(Context context) { - return context.with(CONTEXT_KEY, this); - } -} diff --git a/components/context/src/main/java/datadog/context/propagation/InferredProxyPropagator.java b/components/context/src/main/java/datadog/context/propagation/InferredProxyPropagator.java deleted file mode 100644 index 69e5a0e896e..00000000000 --- a/components/context/src/main/java/datadog/context/propagation/InferredProxyPropagator.java +++ /dev/null @@ -1,74 +0,0 @@ -package datadog.context.propagation; - -import datadog.context.Context; -import datadog.context.InferredProxyContext; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiConsumer; - -public class InferredProxyPropagator implements Propagator { - public static final String INFERRED_PROXY_KEY = "x-dd-proxy"; - /** - * METHOD STUB: InferredProxy is currently not meant to be injected to downstream services Injects - * a context into a downstream service using the given carrier. - * - * @param context the context containing the values to be injected. - * @param carrier the instance that will receive the key/value pairs to propagate. - * @param setter the callback to set key/value pairs into the carrier. - */ - @Override - public void inject(Context context, C carrier, CarrierSetter setter) {} - - /** - * Extracts a context from un upstream service. - * - * @param context the base context to store the extracted values on top, use {@link - * Context#root()} for a default base context. - * @param carrier the instance to fetch the propagated key/value pairs from. - * @param visitor the callback to walk over the carrier and extract its key/value pais. - * @return A context with the extracted values on top of the given base context. - */ - @Override - public Context extract(Context context, C carrier, CarrierVisitor visitor) { - if (context == null || carrier == null || visitor == null) { - return context; - } - InferredProxyContextExtractor extractor = new InferredProxyContextExtractor(); - visitor.forEachKeyValue(carrier, extractor); - - InferredProxyContext extractedContext = extractor.extractedContext; - if (extractedContext == null) { - return context; - } - return extractedContext.storeInto(context); - } - - public static class InferredProxyContextExtractor implements BiConsumer { - private InferredProxyContext extractedContext; - - InferredProxyContextExtractor() {} - - private Map parseInferredProxyHeaders(String input) { - Map parsedHeaders = new HashMap<>(); - return parsedHeaders; - } - - /** - * Performs this operation on the given arguments. - * - * @param key the first input argument from an http header - * @param value the second input argument from an http header - */ - @Override - public void accept(String key, String value) { - if (key == null || key.isEmpty() || !key.startsWith(INFERRED_PROXY_KEY)) { - return; - } - Map inferredProxyMap = parseInferredProxyHeaders(value); - if (extractedContext == null) { - extractedContext = new InferredProxyContext(); - } - extractedContext.putInferredProxyInfo(key, value); - } - } -} diff --git a/components/context/src/test/java/datadog/context/InferredProxyHandlingTest.java b/components/context/src/test/java/datadog/context/InferredProxyHandlingTest.java deleted file mode 100644 index 53ddf5cb12a..00000000000 --- a/components/context/src/test/java/datadog/context/InferredProxyHandlingTest.java +++ /dev/null @@ -1,465 +0,0 @@ -package datadog.context; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import datadog.context.propagation.CarrierVisitor; -import datadog.context.propagation.InferredProxyPropagator; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; // For @Test on nested class methods -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class InferredProxyHandlingTest { - - // Define header key constants locally for the test - static final String PROXY_SYSTEM_KEY = "x-dd-proxy-system"; - static final String PROXY_REQUEST_TIME_MS_KEY = "x-dd-proxy-request-time-ms"; - static final String PROXY_PATH_KEY = "x-dd-proxy-path"; - static final String PROXY_HTTP_METHOD_KEY = "x-dd-proxy-httpmethod"; - static final String PROXY_DOMAIN_NAME_KEY = "x-dd-proxy-domain-name"; - - private InferredProxyPropagator propagator; - - @BeforeEach - void setUp() { - propagator = new InferredProxyPropagator(); - } - - // Moved @MethodSource providers to the outer class and made them static - static Stream validHeadersProviderForPropagator() { - Map allStandard = new HashMap<>(); - allStandard.put(PROXY_SYSTEM_KEY, "aws-apigw"); // The only currently supported system - allStandard.put(PROXY_REQUEST_TIME_MS_KEY, "12345"); - allStandard.put(PROXY_PATH_KEY, "/foo"); - allStandard.put(PROXY_HTTP_METHOD_KEY, "GET"); - allStandard.put(PROXY_DOMAIN_NAME_KEY, "api.example.com"); - - return Stream.of( - Arguments.of( - "all standard headers (aws-apigw)", - allStandard, - "aws-apigw", - "12345", - "/foo", - "GET", - "api.example.com", - null, - null)); - } - - static Stream invalidOrMissingHeadersProviderForPropagator() { // Renamed - Map missingSystem = new HashMap<>(); - missingSystem.put(PROXY_REQUEST_TIME_MS_KEY, "12345"); - missingSystem.put(PROXY_PATH_KEY, "/foo"); - - Map missingTime = new HashMap<>(); - missingTime.put(PROXY_SYSTEM_KEY, "aws-apigw"); - missingTime.put(PROXY_PATH_KEY, "/foo"); - - return Stream.of( - Arguments.of("PROXY_SYSTEM_KEY missing", missingSystem), - Arguments.of("PROXY_REQUEST_TIME_MS_KEY missing", missingTime)); - } - - // Simple Map visitor for tests (can remain static or non-static in outer class) - static class MapVisitor implements CarrierVisitor> { - @Override - public void forEachKeyValue(Map carrier, BiConsumer visitor) { - if (carrier == null) { - return; - } - carrier.forEach(visitor); - } - } - - // Custom visitor to test null key path in the extractor - MOVED HERE and made static - static class NullKeyTestVisitor implements CarrierVisitor> { - private final BiConsumer actualExtractorAccept; - - NullKeyTestVisitor(BiConsumer actualExtractorAccept) { - this.actualExtractorAccept = actualExtractorAccept; - } - - @Override - public void forEachKeyValue(Map carrier, BiConsumer visitor) { - if (actualExtractorAccept != null) { - actualExtractorAccept.accept(null, "valueForNullKey"); - } - } - } - - @Nested - @DisplayName("InferredProxyPropagator Tests") - class PropagatorTests { // Kept non-static - - @ParameterizedTest(name = "{0}") - @MethodSource( - "datadog.context.InferredProxyHandlingTest#validHeadersProviderForPropagator") // Fully - // qualified - // name - @DisplayName("Should extract InferredProxyContext when valid headers are present") - void testSuccessfulExtraction( - String description, - Map headers, - String expectedSystem, - String expectedTimeMs, - String expectedPath, - String expectedMethod, - String expectedDomain, - String expectedExtraKey, - String expectedExtraValue) { - - Context rootContext = Context.root(); - // Now accesses the outer class's propagator instance field - Context extractedOuterContext = propagator.extract(rootContext, headers, new MapVisitor()); - InferredProxyContext inferredProxyContext = - InferredProxyContext.fromContext(extractedOuterContext); - - assertNotNull( - inferredProxyContext, "InferredProxyContext should not be null for: " + description); - Map actualProxyData = inferredProxyContext.getInferredProxyContext(); - assertEquals(expectedSystem, actualProxyData.get(PROXY_SYSTEM_KEY)); - assertEquals(expectedTimeMs, actualProxyData.get(PROXY_REQUEST_TIME_MS_KEY)); - assertEquals(expectedPath, actualProxyData.get(PROXY_PATH_KEY)); - assertEquals(expectedMethod, actualProxyData.get(PROXY_HTTP_METHOD_KEY)); - assertEquals(expectedDomain, actualProxyData.get(PROXY_DOMAIN_NAME_KEY)); - if (expectedExtraKey != null) { - assertEquals(expectedExtraValue, actualProxyData.get(expectedExtraKey)); - } - } - - @ParameterizedTest(name = "{0}") - @MethodSource( - "datadog.context.InferredProxyHandlingTest#invalidOrMissingHeadersProviderForPropagator") // Fully qualified name - @DisplayName("Should create InferredProxyContext even if some critical headers are missing") - void testExtractionWithMissingCriticalHeaders(String description, Map headers) { - Context rootContext = Context.root(); - Context extractedOuterContext = propagator.extract(rootContext, headers, new MapVisitor()); - InferredProxyContext inferredProxyContext = - InferredProxyContext.fromContext(extractedOuterContext); - - assertNotNull( - inferredProxyContext, - "InferredProxyContext should still be created if any x-dd-proxy-* header is present for: " - + description); - Map actualProxyData = inferredProxyContext.getInferredProxyContext(); - - if (headers.containsKey(PROXY_SYSTEM_KEY)) { - assertEquals(headers.get(PROXY_SYSTEM_KEY), actualProxyData.get(PROXY_SYSTEM_KEY)); - } else { - assertNull(actualProxyData.get(PROXY_SYSTEM_KEY)); - } - if (headers.containsKey(PROXY_REQUEST_TIME_MS_KEY)) { - assertEquals( - headers.get(PROXY_REQUEST_TIME_MS_KEY), actualProxyData.get(PROXY_REQUEST_TIME_MS_KEY)); - } else { - assertNull(actualProxyData.get(PROXY_REQUEST_TIME_MS_KEY)); - } - } - - @Test - @DisplayName("Should not extract InferredProxyContext if no relevant headers are present") - void testNoRelevantHeaders() { - Map carrier = new HashMap<>(); - carrier.put("x-unrelated-header", "value"); - carrier.put("another-header", "othervalue"); - Context rootContext = Context.root(); - - Context extractedOuterContext = propagator.extract(rootContext, carrier, new MapVisitor()); - InferredProxyContext inferredProxyContext = - InferredProxyContext.fromContext(extractedOuterContext); - - assertNull( - inferredProxyContext, - "InferredProxyContext should be null if no x-dd-proxy-* headers are found"); - } - - @Test - @DisplayName("Should return original context if carrier is null") - void testNullCarrier() { - InferredProxyContext initialData = - new InferredProxyContext(Collections.singletonMap("test", "value")); - Context rootContext = Context.root().with(InferredProxyContext.CONTEXT_KEY, initialData); - - Context extractedOuterContext = propagator.extract(rootContext, null, new MapVisitor()); - - assertEquals(rootContext, extractedOuterContext, "Context should be unchanged"); - assertEquals( - "value", - InferredProxyContext.fromContext(extractedOuterContext) - .getInferredProxyContext() - .get("test")); - } - - @Test - @DisplayName("Should return original context if visitor is null") - void testNullVisitor() { - Map carrier = Collections.singletonMap(PROXY_SYSTEM_KEY, "aws-apigw"); - InferredProxyContext initialData = - new InferredProxyContext(Collections.singletonMap("test", "value")); - Context rootContext = Context.root().with(InferredProxyContext.CONTEXT_KEY, initialData); - - Context extractedOuterContext = propagator.extract(rootContext, carrier, null); - - assertEquals(rootContext, extractedOuterContext, "Context should be unchanged"); - assertEquals( - "value", - InferredProxyContext.fromContext(extractedOuterContext) - .getInferredProxyContext() - .get("test")); - } - - @Test - @DisplayName("Should return original context if context is null") - void testNullContext() { - Map carrier = Collections.singletonMap(PROXY_SYSTEM_KEY, "aws-apigw"); - Context extractedOuterContext = propagator.extract(null, carrier, new MapVisitor()); - assertNull(extractedOuterContext, "Context should remain null if passed as null"); - } - - @Test - @DisplayName("Extractor should handle multiple proxy headers") - void testMultipleProxyHeaders() { - Map carrier = new HashMap<>(); - carrier.put(PROXY_SYSTEM_KEY, "aws-apigw"); - carrier.put(PROXY_REQUEST_TIME_MS_KEY, "12345"); - carrier.put("x-dd-proxy-custom", "value1"); // First proxy header - carrier.put("x-dd-proxy-another", "value2"); // Second proxy header - - Context rootContext = Context.root(); - Context extractedOuterContext = propagator.extract(rootContext, carrier, new MapVisitor()); - InferredProxyContext inferredProxyContext = - InferredProxyContext.fromContext(extractedOuterContext); - - assertNotNull(inferredProxyContext); - // Check if both headers were stored (covers extractedContext == null being false) - assertEquals( - "value1", inferredProxyContext.getInferredProxyContext().get("x-dd-proxy-custom")); - assertEquals( - "value2", inferredProxyContext.getInferredProxyContext().get("x-dd-proxy-another")); - assertEquals( - "aws-apigw", inferredProxyContext.getInferredProxyContext().get(PROXY_SYSTEM_KEY)); - } - - @Test - @DisplayName("Extractor accept method should handle null/empty keys") - void testExtractorAcceptNullEmptyKeys() { - Context rootContext = Context.root(); - - // Test null key - HashMap doesn't allow null keys. Standard HTTP visitors - // also typically don't yield null keys. Testing this branch is difficult - // without a custom visitor or modifying the source. Relying on coverage report - // or assuming standard carriers won't provide null keys. - - // Test empty key - Map carrierWithEmptyKey = new HashMap<>(); - carrierWithEmptyKey.put("", "emptyKeyValue"); // Add empty key - carrierWithEmptyKey.put(PROXY_SYSTEM_KEY, "aws-apigw"); // Add a valid key too - - Context contextAfterEmpty = - propagator.extract(rootContext, carrierWithEmptyKey, new MapVisitor()); - InferredProxyContext ipcEmpty = InferredProxyContext.fromContext(contextAfterEmpty); - - // The propagator should ignore the empty key entry entirely. - assertNotNull(ipcEmpty, "Context should be created due to valid key"); - assertNull(ipcEmpty.getInferredProxyContext().get(""), "Empty key should not be stored"); - assertEquals( - "aws-apigw", - ipcEmpty.getInferredProxyContext().get(PROXY_SYSTEM_KEY), - "Valid key should still be stored"); - assertEquals(1, ipcEmpty.getInferredProxyContext().size(), "Only valid key should be stored"); - } - - @Test - @DisplayName( - "Extractor accept method should handle explicitly passed null key via custom visitor") - void testExtractorAcceptExplicitNullKey() { - Context rootContext = Context.root(); - Map carrier = new HashMap<>(); // Carrier can be empty for this test - - // We need to get a handle to the internal BiConsumer (the InferredProxyContextExtractor - // instance). - // The extract method will create one. We can pass a visitor that captures it. - - final BiConsumer[] extractorHolder = new BiConsumer[1]; - - CarrierVisitor> capturingVisitor = - (cr, bic) -> { - extractorHolder[0] = bic; // Capture the BiConsumer - // Optionally, call the original MapVisitor if we still want normal processing after - // capture - // new MapVisitor().forEachKeyValue(cr, bic); - }; - - // This first call is primarily to get a reference to the internal extractor - propagator.extract(rootContext, carrier, capturingVisitor); - - assertNotNull(extractorHolder[0], "Failed to capture the internal extractor instance"); - - // Now use a new custom visitor to specifically test the null key path - // on the captured extractor instance (though this isn't how extract is typically used). - // A more direct way to test the BiConsumer if it were accessible or if the design allowed it. - // For now, we directly call accept on the captured one. - extractorHolder[0].accept(null, "valueForNullKey"); - - // The goal is JaCoCo coverage. Asserting internal state of the extractor is hard without - // reflection. - // We can verify that the context remains unchanged or as expected if no valid headers - // processed. - InferredProxyContext ipc = - InferredProxyContext.fromContext( - rootContext); // or context returned by a second extract call - assertNull(ipc, "Context should not have InferredProxyContext from only a null key call"); - } - } - - @Nested - @DisplayName("InferredProxyContext Tests") - class ContextUnitTests { - - @Test - @DisplayName("Default constructor should create an empty context map") - void testDefaultConstructor() { - InferredProxyContext ipc = new InferredProxyContext(); - assertNotNull(ipc.getInferredProxyContext()); - assertTrue(ipc.getInferredProxyContext().isEmpty()); - } - - @Test - @DisplayName("Constructor with map should initialize context map") - void testMapConstructor() { - Map initialData = new HashMap<>(); - initialData.put("key1", "value1"); - initialData.put("key2", "value2"); - - InferredProxyContext ipc = new InferredProxyContext(initialData); - assertNotNull(ipc.getInferredProxyContext()); - assertEquals(2, ipc.getInferredProxyContext().size()); - assertEquals("value1", ipc.getInferredProxyContext().get("key1")); - assertEquals("value2", ipc.getInferredProxyContext().get("key2")); - - initialData.put("key3", "value3"); // Modify original map - assertNull(ipc.getInferredProxyContext().get("key3"), "Internal map should be a copy"); - } - - @Test - @DisplayName("putInferredProxyInfo should add to the context map") - void testPutInfo() { - InferredProxyContext ipc = new InferredProxyContext(); - ipc.putInferredProxyInfo("system", "aws-apigw"); - ipc.putInferredProxyInfo("time", "12345"); - - Map contextMap = ipc.getInferredProxyContext(); - assertEquals(2, contextMap.size()); - assertEquals("aws-apigw", contextMap.get("system")); - assertEquals("12345", contextMap.get("time")); - - ipc.putInferredProxyInfo("system", "azure-func"); // Overwrite - assertEquals("azure-func", contextMap.get("system")); - assertEquals(2, contextMap.size()); - } - - @Test - @DisplayName("removeInferredProxyInfo should remove from the context map") - void testRemoveInfo() { - Map initialData = new HashMap<>(); - initialData.put("key1", "value1"); - initialData.put("key2", "value2"); - InferredProxyContext ipc = new InferredProxyContext(initialData); - - ipc.removeInferredProxyInfo("key1"); - Map contextMap = ipc.getInferredProxyContext(); - assertEquals(1, contextMap.size()); - assertNull(contextMap.get("key1")); - assertEquals("value2", contextMap.get("key2")); - - ipc.removeInferredProxyInfo("nonexistent"); // Remove non-existent - assertEquals(1, contextMap.size()); - } - - @Test - @DisplayName("storeInto and fromContext should correctly attach and retrieve the context") - void testStoreAndFromContext() { - InferredProxyContext ipcToStore = new InferredProxyContext(); - ipcToStore.putInferredProxyInfo("customKey", "customValue"); - - Context rootContext = Context.root(); - Context contextWithValue = ipcToStore.storeInto(rootContext); - assertNotNull(contextWithValue); - - InferredProxyContext retrievedIpc = InferredProxyContext.fromContext(contextWithValue); - assertNotNull(retrievedIpc); - assertEquals("customValue", retrievedIpc.getInferredProxyContext().get("customKey")); - - assertNull( - InferredProxyContext.fromContext(rootContext), - "Original root context should not be affected"); - - Context cleanContext = Context.root(); - assertNull( - InferredProxyContext.fromContext(cleanContext), - "fromContext on clean context should be null"); - } - - @Test - @DisplayName("getInferredProxyContext should return an unmodifiable map or a copy") - void testGetInferredProxyContextImmutability() { - InferredProxyContext ipc = new InferredProxyContext(); - ipc.putInferredProxyInfo("key1", "value1"); - - Map retrievedMap = ipc.getInferredProxyContext(); - assertNotNull(retrievedMap); - assertEquals("value1", retrievedMap.get("key1")); - - boolean threwUnsupported = false; - try { - retrievedMap.put("newKey", "newValue"); - } catch (UnsupportedOperationException e) { - threwUnsupported = true; - } - // Depending on whether InferredProxyContext.getInferredProxyContext() returns a direct - // reference or a copy, - // this assertion might change. If it returns a direct mutable reference, threwUnsupported - // will be false. - // If it returns an unmodifiable view or a copy, attempts to modify might throw or simply not - // affect the original. - // For now, we check that the original context was not changed. - assertEquals( - 1, ipc.getInferredProxyContext().size(), "Internal map size should remain unchanged"); - assertEquals( - "value1", - ipc.getInferredProxyContext().get("key1"), - "Internal map content should remain unchanged"); - // If it MUST be unmodifiable, add: assertTrue(threwUnsupported, "Retrieved map should be - // unmodifiable"); - } - - @Test - @DisplayName("Constructor with null map should create an empty context map") - void testNullMapConstructor() { - InferredProxyContext ipc = new InferredProxyContext(null); - assertNotNull(ipc.getInferredProxyContext()); - assertTrue(ipc.getInferredProxyContext().isEmpty()); - } - - @Test - @DisplayName("Constructor with empty map should create an empty context map") - void testEmptyMapConstructor() { - Map emptyMap = Collections.emptyMap(); - InferredProxyContext ipc = new InferredProxyContext(emptyMap); - assertNotNull(ipc.getInferredProxyContext()); - assertTrue(ipc.getInferredProxyContext().isEmpty()); - } - } -} 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 41330ffbe4c..666645ba002 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,7 +8,6 @@ import static datadog.trace.bootstrap.instrumentation.decorator.http.HttpResourceDecorator.HTTP_RESOURCE_DECORATOR; import datadog.appsec.api.blocking.BlockingException; -import datadog.context.InferredProxyContext; import datadog.context.propagation.Propagators; import datadog.trace.api.Config; import datadog.trace.api.DDTags; @@ -22,6 +21,7 @@ import datadog.trace.api.gateway.IGSpanInfo; import datadog.trace.api.gateway.RequestContext; import datadog.trace.api.gateway.RequestContextSlot; +import datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders; import datadog.trace.api.interceptor.MutableSpan; import datadog.trace.api.naming.SpanNaming; import datadog.trace.bootstrap.ActiveSubsystems; @@ -598,18 +598,15 @@ private AgentSpan startSpanWithInferredProxy( datadog.context.Context fullContextForInferredProxy, AgentSpanContext.Extracted standardExtractedContext) { - InferredProxyContext inferredProxy = - InferredProxyContext.fromContext(fullContextForInferredProxy); + InferredProxyHeaders headers = InferredProxyHeaders.fromContext(fullContextForInferredProxy); - if (inferredProxy == null) { + if (headers == null) { return null; } - Map headers = inferredProxy.getInferredProxyContext(); - // Check if timestamp and proxy system are present - String startTimeStr = headers.get(PROXY_START_TIME_MS); - String proxySystem = headers.get(PROXY_SYSTEM); + String startTimeStr = headers.getValue(PROXY_START_TIME_MS); + String proxySystem = headers.getValue(PROXY_SYSTEM); if (startTimeStr == null || proxySystem == null @@ -634,12 +631,14 @@ private AgentSpan startSpanWithInferredProxy( apiGtwSpan.setTag(Tags.COMPONENT, proxySystem); apiGtwSpan.setTag( - DDTags.RESOURCE_NAME, headers.get(PROXY_HTTP_METHOD) + " " + headers.get(PROXY_PATH)); - apiGtwSpan.setTag(DDTags.SERVICE_NAME, headers.get(PROXY_DOMAIN_NAME)); + DDTags.RESOURCE_NAME, + headers.getValue(PROXY_HTTP_METHOD) + " " + headers.getValue(PROXY_PATH)); + apiGtwSpan.setTag(DDTags.SERVICE_NAME, headers.getValue(PROXY_DOMAIN_NAME)); apiGtwSpan.setTag(DDTags.SPAN_TYPE, "web"); - apiGtwSpan.setTag(Tags.HTTP_METHOD, headers.get(PROXY_HTTP_METHOD)); - apiGtwSpan.setTag(Tags.HTTP_URL, headers.get(PROXY_DOMAIN_NAME) + headers.get(PROXY_PATH)); - apiGtwSpan.setTag("stage", headers.get(STAGE)); + apiGtwSpan.setTag(Tags.HTTP_METHOD, headers.getValue(PROXY_HTTP_METHOD)); + apiGtwSpan.setTag( + Tags.HTTP_URL, headers.getValue(PROXY_DOMAIN_NAME) + headers.getValue(PROXY_PATH)); + apiGtwSpan.setTag("stage", headers.getValue(STAGE)); apiGtwSpan.setTag("_dd.inferred_span", 1); return apiGtwSpan; } 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 99fca082ecd..2b93f620e05 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 @@ -22,7 +22,6 @@ import datadog.communication.ddagent.SharedCommunicationObjects; import datadog.communication.monitor.Monitoring; import datadog.communication.monitor.Recording; -import datadog.context.propagation.InferredProxyPropagator; import datadog.context.propagation.Propagators; import datadog.trace.api.ClassloaderConfigurationOverrides; import datadog.trace.api.Config; @@ -44,6 +43,7 @@ import datadog.trace.api.gateway.RequestContext; import datadog.trace.api.gateway.RequestContextSlot; import datadog.trace.api.gateway.SubscriptionService; +import datadog.trace.api.gateway.inferredproxy.InferredProxyPropagator; import datadog.trace.api.interceptor.MutableSpan; import datadog.trace.api.interceptor.TraceInterceptor; import datadog.trace.api.internal.TraceSegment; diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeaders.java b/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeaders.java new file mode 100644 index 00000000000..0d649d66d44 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeaders.java @@ -0,0 +1,40 @@ +package datadog.trace.api.gateway.inferredproxy; + +import static datadog.context.ContextKey.named; + +import datadog.context.Context; +import datadog.context.ContextKey; +import datadog.context.ImplicitContextKeyed; +import java.util.Collections; +import java.util.Map; +import javax.annotation.Nullable; + +public class InferredProxyHeaders implements ImplicitContextKeyed { + private static final ContextKey CONTEXT_KEY = named("inferred-proxy-key"); + private final Map values; + + public static InferredProxyHeaders fromValues(Map values) { + return new InferredProxyHeaders(values); + } + + public static InferredProxyHeaders fromContext(Context context) { + return context.get(CONTEXT_KEY); + } + + private InferredProxyHeaders(Map values) { + this.values = values == null ? Collections.emptyMap() : values; + } + + public @Nullable String getValue(String key) { + return this.values.get(key); + } + + public int size() { + return this.values.size(); + } + + @Override + public Context storeInto(Context context) { + return context.with(CONTEXT_KEY, this); + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagator.java b/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagator.java new file mode 100644 index 00000000000..141e63a3643 --- /dev/null +++ b/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagator.java @@ -0,0 +1,48 @@ +package datadog.trace.api.gateway.inferredproxy; + +import datadog.context.Context; +import datadog.context.propagation.CarrierSetter; +import datadog.context.propagation.CarrierVisitor; +import datadog.context.propagation.Propagator; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import javax.annotation.ParametersAreNonnullByDefault; + +/** Inferred proxy propagator. Only extract, not meant for injection. */ +@ParametersAreNonnullByDefault +public class InferredProxyPropagator implements Propagator { + private static final String INFERRED_PROXY_KEY_PREFIX = "x-dd-proxy-"; + + @Override + public void inject(Context context, C carrier, CarrierSetter setter) {} + + @Override + public Context extract(Context context, C carrier, CarrierVisitor visitor) { + if (context == null || carrier == null || visitor == null) { + return context; + } + InferredProxyContextExtractor extractor = new InferredProxyContextExtractor(); + visitor.forEachKeyValue(carrier, extractor); + if (extractor.values != null) { + context = context.with(InferredProxyHeaders.fromValues(extractor.values)); + } + return context; + } + + /** Extract inferred proxy related headers into a map. */ + private static class InferredProxyContextExtractor implements BiConsumer { + private Map values; + + @Override + public void accept(String key, String value) { + if (key == null || key.isEmpty() || !key.startsWith(INFERRED_PROXY_KEY_PREFIX)) { + return; + } + if (values == null) { + this.values = new HashMap<>(); + } + this.values.put(key, value); + } + } +} diff --git a/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java b/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java new file mode 100644 index 00000000000..c0abf282a20 --- /dev/null +++ b/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java @@ -0,0 +1,60 @@ +package datadog.trace.api.gateway.inferredproxy; + +import static datadog.context.Context.root; +import static datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders.fromContext; +import static datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders.fromValues; +import static java.util.Collections.emptyMap; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import datadog.context.Context; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +@DisplayName("InferredProxyContext Tests") +class InferredProxyHeadersTests { + @Test + @DisplayName("Constructor with map should initialize context map") + void testMapConstructor() { + Map initialData = new HashMap<>(); + initialData.put("key1", "value1"); + initialData.put("key2", "value2"); + + InferredProxyHeaders headers = InferredProxyHeaders.fromValues(initialData); + assertEquals(2, headers.size()); + assertEquals("value1", headers.getValue("key1")); + assertEquals("value2", headers.getValue("key2")); + } + + @Test + @DisplayName("storeInto and fromContext should correctly attach and retrieve the context") + void testStoreAndFromContext() { + InferredProxyHeaders inferredProxyHeaders = InferredProxyHeaders.fromValues(null); + Context context = inferredProxyHeaders.storeInto(root()); + assertNotNull(context); + + InferredProxyHeaders retrieved = fromContext(context); + assertNotNull(retrieved); + + assertNull(fromContext(root()), "fromContext on empty context should be null"); + } + + @Test + @DisplayName("Constructor with null map should create an empty context map") + void testNullMapConstructor() { + InferredProxyHeaders inferredProxyHeaders = InferredProxyHeaders.fromValues(null); + assertNotNull(inferredProxyHeaders); + assertEquals(0, inferredProxyHeaders.size()); + } + + @Test + @DisplayName("Constructor with empty map should create an empty context map") + void testEmptyMapConstructor() { + InferredProxyHeaders inferredProxyHeaders = fromValues(emptyMap()); + assertNotNull(inferredProxyHeaders); + assertEquals(0, inferredProxyHeaders.size()); + } +} diff --git a/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagatorTests.java b/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagatorTests.java new file mode 100644 index 00000000000..e3a5c009130 --- /dev/null +++ b/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagatorTests.java @@ -0,0 +1,203 @@ +package datadog.trace.api.gateway.inferredproxy; + +import static datadog.context.Context.root; +import static datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders.fromContext; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import datadog.context.Context; +import datadog.context.propagation.CarrierVisitor; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.stream.Stream; +import javax.annotation.ParametersAreNonnullByDefault; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@DisplayName("InferredProxyPropagator Tests") +class InferredProxyPropagatorTests { // Kept non-static + private static final String PROXY_SYSTEM_KEY = "x-dd-proxy-system"; + private static final String PROXY_REQUEST_TIME_MS_KEY = "x-dd-proxy-request-time-ms"; + private static final String PROXY_PATH_KEY = "x-dd-proxy-path"; + private static final String PROXY_HTTP_METHOD_KEY = "x-dd-proxy-httpmethod"; + private static final String PROXY_DOMAIN_NAME_KEY = "x-dd-proxy-domain-name"; + private static final MapVisitor MAP_VISITOR = new MapVisitor(); + + static Stream validHeadersProviderForPropagator() { + Map allStandard = new HashMap<>(); + allStandard.put(PROXY_SYSTEM_KEY, "aws-apigw"); // The only currently supported system + allStandard.put(PROXY_REQUEST_TIME_MS_KEY, "12345"); + allStandard.put(PROXY_PATH_KEY, "/foo"); + allStandard.put(PROXY_HTTP_METHOD_KEY, "GET"); + allStandard.put(PROXY_DOMAIN_NAME_KEY, "api.example.com"); + + return Stream.of( + Arguments.of( + "all standard headers (aws-apigw)", + allStandard, + "aws-apigw", + "12345", + "/foo", + "GET", + "api.example.com", + null, + null)); + } + + static Stream invalidOrMissingHeadersProviderForPropagator() { // Renamed + Map missingSystem = new HashMap<>(); + missingSystem.put(PROXY_REQUEST_TIME_MS_KEY, "12345"); + missingSystem.put(PROXY_PATH_KEY, "/foo"); + + Map missingTime = new HashMap<>(); + missingTime.put(PROXY_SYSTEM_KEY, "aws-apigw"); + missingTime.put(PROXY_PATH_KEY, "/foo"); + + return Stream.of( + Arguments.of("PROXY_SYSTEM_KEY missing", missingSystem), + Arguments.of("PROXY_REQUEST_TIME_MS_KEY missing", missingTime)); + } + + private InferredProxyPropagator propagator; + + @BeforeEach + void setUp() { + propagator = new InferredProxyPropagator(); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("validHeadersProviderForPropagator") + @DisplayName("Should extract InferredProxyContext when valid headers are present") + void testSuccessfulExtraction( + String description, + Map headers, + String expectedSystem, + String expectedTimeMs, + String expectedPath, + String expectedMethod, + String expectedDomain, + String expectedExtraKey, + String expectedExtraValue) { + + // Now accesses the outer class's propagator instance field + Context extractedOuterContext = this.propagator.extract(root(), headers, MAP_VISITOR); + InferredProxyHeaders inferredProxyHeaders = fromContext(extractedOuterContext); + + assertNotNull( + inferredProxyHeaders, "InferredProxyContext should not be null for: " + description); + assertEquals(expectedSystem, inferredProxyHeaders.getValue(PROXY_SYSTEM_KEY)); + assertEquals(expectedTimeMs, inferredProxyHeaders.getValue(PROXY_REQUEST_TIME_MS_KEY)); + assertEquals(expectedPath, inferredProxyHeaders.getValue(PROXY_PATH_KEY)); + assertEquals(expectedMethod, inferredProxyHeaders.getValue(PROXY_HTTP_METHOD_KEY)); + assertEquals(expectedDomain, inferredProxyHeaders.getValue(PROXY_DOMAIN_NAME_KEY)); + if (expectedExtraKey != null) { + assertEquals(expectedExtraValue, inferredProxyHeaders.getValue(expectedExtraKey)); + } + } + + @ParameterizedTest(name = "{0}") + @MethodSource("invalidOrMissingHeadersProviderForPropagator") + @DisplayName("Should create InferredProxyContext even if some critical headers are missing") + void testExtractionWithMissingCriticalHeaders(String description, Map headers) { + Context rootContext = root(); + Context extractedOuterContext = this.propagator.extract(rootContext, headers, MAP_VISITOR); + InferredProxyHeaders inferredProxyHeaders = fromContext(extractedOuterContext); + + assertNotNull( + inferredProxyHeaders, + "InferredProxyContext should still be created if any x-dd-proxy-* header is present for: " + + description); + + if (headers.containsKey(PROXY_SYSTEM_KEY)) { + assertEquals(headers.get(PROXY_SYSTEM_KEY), inferredProxyHeaders.getValue(PROXY_SYSTEM_KEY)); + } else { + assertNull(inferredProxyHeaders.getValue(PROXY_SYSTEM_KEY)); + } + if (headers.containsKey(PROXY_REQUEST_TIME_MS_KEY)) { + assertEquals( + headers.get(PROXY_REQUEST_TIME_MS_KEY), + inferredProxyHeaders.getValue(PROXY_REQUEST_TIME_MS_KEY)); + } else { + assertNull(inferredProxyHeaders.getValue(PROXY_REQUEST_TIME_MS_KEY)); + } + } + + @Test + @DisplayName("Should not extract InferredProxyContext if no relevant headers are present") + void testNoRelevantHeaders() { + Map carrier = new HashMap<>(); + carrier.put("x-unrelated-header", "value"); + carrier.put("another-header", "othervalue"); + + Context extractedOuterContext = this.propagator.extract(root(), carrier, MAP_VISITOR); + InferredProxyHeaders inferredProxyHeaders = fromContext(extractedOuterContext); + + assertNull( + inferredProxyHeaders, + "InferredProxyContext should be null if no x-dd-proxy-* headers are found"); + } + + @Test + @DisplayName("Extractor should handle multiple proxy headers") + void testMultipleProxyHeaders() { + Map carrier = new HashMap<>(); + carrier.put(PROXY_SYSTEM_KEY, "aws-apigw"); + carrier.put(PROXY_REQUEST_TIME_MS_KEY, "12345"); + carrier.put("x-dd-proxy-custom", "value1"); // First proxy header + carrier.put("x-dd-proxy-another", "value2"); // Second proxy header + + Context extractedOuterContext = this.propagator.extract(root(), carrier, MAP_VISITOR); + InferredProxyHeaders inferredProxyHeaders = fromContext(extractedOuterContext); + + assertNotNull(inferredProxyHeaders); + // Check if both headers were stored (covers extractedContext == null being false) + assertEquals("value1", inferredProxyHeaders.getValue("x-dd-proxy-custom")); + assertEquals("value2", inferredProxyHeaders.getValue("x-dd-proxy-another")); + assertEquals("aws-apigw", inferredProxyHeaders.getValue(PROXY_SYSTEM_KEY)); + } + + @Test + @DisplayName("Extractor accept method should handle null/empty keys") + void testExtractorAcceptNullEmptyKeys() { + + // Test null key - HashMap doesn't allow null keys. Standard HTTP visitors + // also typically don't yield null keys. Testing this branch is difficult + // without a custom visitor or modifying the source. Relying on coverage report + // or assuming standard carriers won't provide null keys. + + // Test empty key + Map carrierWithEmptyKey = new HashMap<>(); + carrierWithEmptyKey.put("", "emptyKeyValue"); // Add empty key + carrierWithEmptyKey.put(PROXY_SYSTEM_KEY, "aws-apigw"); // Add a valid key too + + Context contextAfterEmpty = this.propagator.extract(root(), carrierWithEmptyKey, MAP_VISITOR); + InferredProxyHeaders inferredProxyHeaders = fromContext(contextAfterEmpty); + + // The propagator should ignore the empty key entry entirely. + assertNotNull(inferredProxyHeaders, "Context should be created due to valid key"); + assertNull(inferredProxyHeaders.getValue(""), "Empty key should not be stored"); + assertEquals( + "aws-apigw", + inferredProxyHeaders.getValue(PROXY_SYSTEM_KEY), + "Valid key should still be stored"); + assertEquals(1, inferredProxyHeaders.size(), "Only valid key should be stored"); + } + + // Simple Map visitor for tests (can remain static or non-static in outer class) + @ParametersAreNonnullByDefault + private static class MapVisitor implements CarrierVisitor> { + @Override + public void forEachKeyValue(Map carrier, BiConsumer visitor) { + if (carrier == null) { + return; + } + carrier.forEach(visitor); + } + } +} From 276f07a3320246c17a4f0e1a1ea3911e2089270e Mon Sep 17 00:00:00 2001 From: Bruce Bujon Date: Mon, 12 May 2025 11:57:12 +0200 Subject: [PATCH 2/2] feat(gateway): Fix inferred gateway span design Move propagator to dd-trace-core --- .../instrumentation/decorator/HttpServerDecorator.java | 2 +- .../src/main/java/datadog/trace/core/CoreTracer.java | 2 +- .../trace/core/propagation}/InferredProxyPropagator.java | 3 ++- .../core/propagation}/InferredProxyPropagatorTests.java | 5 +++-- .../gateway/{inferredproxy => }/InferredProxyHeaders.java | 2 +- .../api/gateway/inferredproxy/InferredProxyHeadersTests.java | 5 +++-- 6 files changed, 11 insertions(+), 8 deletions(-) rename {internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy => dd-trace-core/src/main/java/datadog/trace/core/propagation}/InferredProxyPropagator.java (94%) rename {internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy => dd-trace-core/src/test/java/datadog/trace/core/propagation}/InferredProxyPropagatorTests.java (98%) rename internal-api/src/main/java/datadog/trace/api/gateway/{inferredproxy => }/InferredProxyHeaders.java (95%) 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 666645ba002..0ac09020013 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 @@ -19,9 +19,9 @@ import datadog.trace.api.gateway.CallbackProvider; import datadog.trace.api.gateway.Flow; import datadog.trace.api.gateway.IGSpanInfo; +import datadog.trace.api.gateway.InferredProxyHeaders; import datadog.trace.api.gateway.RequestContext; import datadog.trace.api.gateway.RequestContextSlot; -import datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders; import datadog.trace.api.interceptor.MutableSpan; import datadog.trace.api.naming.SpanNaming; import datadog.trace.bootstrap.ActiveSubsystems; 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 2b93f620e05..2c51878ff44 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 @@ -43,7 +43,6 @@ import datadog.trace.api.gateway.RequestContext; import datadog.trace.api.gateway.RequestContextSlot; import datadog.trace.api.gateway.SubscriptionService; -import datadog.trace.api.gateway.inferredproxy.InferredProxyPropagator; import datadog.trace.api.interceptor.MutableSpan; import datadog.trace.api.interceptor.TraceInterceptor; import datadog.trace.api.internal.TraceSegment; @@ -90,6 +89,7 @@ import datadog.trace.core.monitor.TracerHealthMetrics; import datadog.trace.core.propagation.ExtractedContext; import datadog.trace.core.propagation.HttpCodec; +import datadog.trace.core.propagation.InferredProxyPropagator; import datadog.trace.core.propagation.PropagationTags; import datadog.trace.core.propagation.TracingPropagator; import datadog.trace.core.propagation.XRayPropagator; diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagator.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/InferredProxyPropagator.java similarity index 94% rename from internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagator.java rename to dd-trace-core/src/main/java/datadog/trace/core/propagation/InferredProxyPropagator.java index 141e63a3643..afa5b722f27 100644 --- a/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagator.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/InferredProxyPropagator.java @@ -1,9 +1,10 @@ -package datadog.trace.api.gateway.inferredproxy; +package datadog.trace.core.propagation; import datadog.context.Context; import datadog.context.propagation.CarrierSetter; import datadog.context.propagation.CarrierVisitor; import datadog.context.propagation.Propagator; +import datadog.trace.api.gateway.InferredProxyHeaders; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; diff --git a/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagatorTests.java b/dd-trace-core/src/test/java/datadog/trace/core/propagation/InferredProxyPropagatorTests.java similarity index 98% rename from internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagatorTests.java rename to dd-trace-core/src/test/java/datadog/trace/core/propagation/InferredProxyPropagatorTests.java index e3a5c009130..35f786fbe57 100644 --- a/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyPropagatorTests.java +++ b/dd-trace-core/src/test/java/datadog/trace/core/propagation/InferredProxyPropagatorTests.java @@ -1,13 +1,14 @@ -package datadog.trace.api.gateway.inferredproxy; +package datadog.trace.core.propagation; import static datadog.context.Context.root; -import static datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders.fromContext; +import static datadog.trace.api.gateway.InferredProxyHeaders.fromContext; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import datadog.context.Context; import datadog.context.propagation.CarrierVisitor; +import datadog.trace.api.gateway.InferredProxyHeaders; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeaders.java b/internal-api/src/main/java/datadog/trace/api/gateway/InferredProxyHeaders.java similarity index 95% rename from internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeaders.java rename to internal-api/src/main/java/datadog/trace/api/gateway/InferredProxyHeaders.java index 0d649d66d44..2f0ad7ee94b 100644 --- a/internal-api/src/main/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeaders.java +++ b/internal-api/src/main/java/datadog/trace/api/gateway/InferredProxyHeaders.java @@ -1,4 +1,4 @@ -package datadog.trace.api.gateway.inferredproxy; +package datadog.trace.api.gateway; import static datadog.context.ContextKey.named; diff --git a/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java b/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java index c0abf282a20..fee8fa52671 100644 --- a/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java +++ b/internal-api/src/test/java/datadog/trace/api/gateway/inferredproxy/InferredProxyHeadersTests.java @@ -1,14 +1,15 @@ package datadog.trace.api.gateway.inferredproxy; import static datadog.context.Context.root; -import static datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders.fromContext; -import static datadog.trace.api.gateway.inferredproxy.InferredProxyHeaders.fromValues; +import static datadog.trace.api.gateway.InferredProxyHeaders.fromContext; +import static datadog.trace.api.gateway.InferredProxyHeaders.fromValues; import static java.util.Collections.emptyMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import datadog.context.Context; +import datadog.trace.api.gateway.InferredProxyHeaders; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.DisplayName;