diff --git a/communication/src/main/java/datadog/communication/BackendApiFactory.java b/communication/src/main/java/datadog/communication/BackendApiFactory.java index 2ac0447fc7d..4ea35cb8596 100644 --- a/communication/src/main/java/datadog/communication/BackendApiFactory.java +++ b/communication/src/main/java/datadog/communication/BackendApiFactory.java @@ -1,13 +1,20 @@ package datadog.communication; +import static java.util.Collections.emptyMap; +import static java.util.Collections.unmodifiableMap; + import datadog.communication.ddagent.DDAgentFeaturesDiscovery; import datadog.communication.ddagent.SharedCommunicationObjects; import datadog.communication.http.HttpRetryPolicy; import datadog.trace.api.Config; import datadog.trace.api.intake.Intake; import datadog.trace.util.throwable.FatalAgentMisconfigurationError; +import java.util.HashMap; +import java.util.Map; import javax.annotation.Nullable; import okhttp3.HttpUrl; +import okhttp3.OkHttpClient; +import okhttp3.Request; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,10 +24,19 @@ public class BackendApiFactory { private final Config config; private final SharedCommunicationObjects sharedCommunicationObjects; + private final Map requestHeaders; public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommunicationObjects) { + this(config, sharedCommunicationObjects, emptyMap()); + } + + public BackendApiFactory( + Config config, + SharedCommunicationObjects sharedCommunicationObjects, + Map requestHeaders) { this.config = config; this.sharedCommunicationObjects = sharedCommunicationObjects; + this.requestHeaders = unmodifiableMap(new HashMap<>(requestHeaders)); } public @Nullable BackendApi createBackendApi(Intake intake) { @@ -60,7 +76,7 @@ public BackendApi createDirectIntakeApi(Intake intake, boolean responseCompressi apiKey, traceId, retryPolicyFactory(), - sharedCommunicationObjects.getIntakeHttpClient(), + withRequestHeaders(sharedCommunicationObjects.getIntakeHttpClient()), responseCompression); } @@ -98,10 +114,27 @@ public BackendApi createDirectIntakeApi(Intake intake, boolean responseCompressi evpProxyUrl, subdomain, retryPolicyFactory, - sharedCommunicationObjects.agentHttpClient, + withRequestHeaders(sharedCommunicationObjects.agentHttpClient), responseCompression); } + private OkHttpClient withRequestHeaders(final OkHttpClient httpClient) { + if (requestHeaders.isEmpty()) { + return httpClient; + } + return httpClient + .newBuilder() + .addInterceptor( + chain -> { + final Request.Builder requestBuilder = chain.request().newBuilder(); + for (Map.Entry header : requestHeaders.entrySet()) { + requestBuilder.header(header.getKey(), header.getValue()); + } + return chain.proceed(requestBuilder.build()); + }) + .build(); + } + private static HttpRetryPolicy.Factory retryPolicyFactory() { return new HttpRetryPolicy.Factory(5, 100, 2.0, true); } diff --git a/communication/src/test/java/datadog/communication/BackendApiFactoryTest.java b/communication/src/test/java/datadog/communication/BackendApiFactoryTest.java index 726c34a7f73..d81000d43d2 100644 --- a/communication/src/test/java/datadog/communication/BackendApiFactoryTest.java +++ b/communication/src/test/java/datadog/communication/BackendApiFactoryTest.java @@ -1,6 +1,7 @@ package datadog.communication; import static datadog.communication.ddagent.DDAgentFeaturesDiscovery.V4_EVP_PROXY_ENDPOINT; +import static java.util.Collections.singletonMap; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -45,7 +46,9 @@ void advertisedEvpProxyEndpointSupportsDisabledResponseCompression() throws Exce final FakeFeaturesDiscovery discovery = new FakeFeaturesDiscovery(V4_EVP_PROXY_ENDPOINT); final BackendApiFactory factory = new BackendApiFactory( - Config.get(), sharedCommunicationObjects(discovery, agent.url("/"))); + Config.get(), + sharedCommunicationObjects(discovery, agent.url("/")), + singletonMap("DD-EVP-ORIGIN", "dd-trace-java")); final BackendApi api = factory.createBackendApi(Intake.EVENT_PLATFORM, false); assertNotNull(api); @@ -58,6 +61,9 @@ void advertisedEvpProxyEndpointSupportsDisabledResponseCompression() throws Exce final RecordedRequest request = agent.takeRequest(); assertEquals("/evp_proxy/v4/api/v2/flagevaluation", request.getPath()); + assertEquals("event-platform-intake", request.getHeader("X-Datadog-EVP-Subdomain")); + assertEquals("dd-trace-java", request.getHeader("DD-EVP-ORIGIN")); + assertEquals("identity", request.getHeader("Accept-Encoding")); } finally { agent.shutdown(); } diff --git a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagBackendApiFactory.java b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagBackendApiFactory.java index 0dbf9c74254..8d5314d911c 100644 --- a/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagBackendApiFactory.java +++ b/products/feature-flagging/feature-flagging-lib/src/main/java/com/datadog/featureflag/FeatureFlagBackendApiFactory.java @@ -1,13 +1,17 @@ package com.datadog.featureflag; import static datadog.trace.api.featureflag.config.FeatureFlaggingConfig.CONFIGURATION_SOURCE_AGENTLESS; +import static java.util.Collections.unmodifiableMap; import datadog.communication.BackendApi; import datadog.communication.BackendApiFactory; import datadog.communication.ddagent.SharedCommunicationObjects; +import datadog.communication.ddagent.TracerVersion; import datadog.communication.http.HttpRetryPolicy; import datadog.trace.api.Config; import datadog.trace.api.intake.Intake; +import java.util.HashMap; +import java.util.Map; import javax.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,6 +20,7 @@ final class FeatureFlagBackendApiFactory { private static final Logger LOGGER = LoggerFactory.getLogger(FeatureFlagBackendApiFactory.class); + static final Map REQUEST_HEADERS = requestHeaders(); private final Config config; private final BackendApiFactory backendApiFactory; @@ -25,7 +30,10 @@ final class FeatureFlagBackendApiFactory { final Config config, final SharedCommunicationObjects sharedCommunicationObjects, final FeatureFlagEventType eventType) { - this(config, new BackendApiFactory(config, sharedCommunicationObjects), eventType); + this( + config, + new BackendApiFactory(config, sharedCommunicationObjects, REQUEST_HEADERS), + eventType); } FeatureFlagBackendApiFactory( @@ -78,6 +86,13 @@ BackendApi create() { return null; } + private static Map requestHeaders() { + final Map headers = new HashMap<>(2); + headers.put("DD-EVP-ORIGIN", "dd-trace-java"); + headers.put("DD-EVP-ORIGIN-VERSION", TracerVersion.TRACER_VERSION); + return unmodifiableMap(headers); + } + private boolean hasDirectCredentials() { final String apiKey = config.getApiKey(); return apiKey != null && !apiKey.isEmpty(); diff --git a/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/FeatureFlagBackendApiFactoryTest.java b/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/FeatureFlagBackendApiFactoryTest.java index 8b117742715..3544e66b02c 100644 --- a/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/FeatureFlagBackendApiFactoryTest.java +++ b/products/feature-flagging/feature-flagging-lib/src/test/java/com/datadog/featureflag/FeatureFlagBackendApiFactoryTest.java @@ -4,6 +4,7 @@ import static com.datadog.featureflag.FeatureFlagEventType.FLAG_EVALUATION; import static datadog.trace.api.featureflag.config.FeatureFlaggingConfig.CONFIGURATION_SOURCE_AGENTLESS; import static datadog.trace.api.featureflag.config.FeatureFlaggingConfig.CONFIGURATION_SOURCE_REMOTE_CONFIG; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; @@ -14,6 +15,7 @@ import datadog.communication.BackendApi; import datadog.communication.BackendApiFactory; +import datadog.communication.ddagent.TracerVersion; import datadog.communication.http.HttpRetryPolicy; import datadog.trace.api.Config; import datadog.trace.api.intake.Intake; @@ -21,6 +23,15 @@ class FeatureFlagBackendApiFactoryTest { + @Test + void configuresSdkIdentityHeadersForAllFeatureFlagEventTypes() { + assertEquals( + "dd-trace-java", FeatureFlagBackendApiFactory.REQUEST_HEADERS.get("DD-EVP-ORIGIN")); + assertEquals( + TracerVersion.TRACER_VERSION, + FeatureFlagBackendApiFactory.REQUEST_HEADERS.get("DD-EVP-ORIGIN-VERSION")); + } + @Test void remoteConfigUsesOnlyLocalEvpProxy() { final Config config = config(CONFIGURATION_SOURCE_REMOTE_CONFIG, "api-key");