From eabb2908d2795770a59e30c227fbfe0f1e8177c6 Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Thu, 2 Oct 2025 18:59:39 +0200 Subject: [PATCH 1/7] Create shared DD intake HTTP client --- .../communication/BackendApiFactory.java | 15 +++---- .../ddagent/SharedCommunicationObjects.java | 42 ++++++++++++++++--- .../communication/http/OkHttpUtils.java | 11 +++-- ...dCommunicationsObjectsSpecification.groovy | 6 +-- .../civisibility/CiVisibilityServices.java | 2 +- .../appsec/benchmark/AppSecBenchmark.java | 4 +- .../appsec/AppSecSystemSpecification.groovy | 2 +- .../test/InstrumentationSpecification.groovy | 2 +- .../metrics/ConflatingMetricsAggregator.java | 2 +- .../trace/common/writer/DDAgentWriter.java | 2 +- .../trace/common/writer/WriterFactory.java | 5 ++- .../DefaultDataStreamsMonitoring.java | 2 +- .../TracerConnectionReliabilityTest.groovy | 4 +- .../common/writer/WriterFactoryTest.groovy | 4 +- .../datadog/trace/core/CoreTracerTest.groovy | 8 ++-- .../trace/core/TracingConfigPollerTest.groovy | 4 +- .../datastreams/DataStreamsWritingTest.groovy | 4 +- .../datadog/telemetry/TelemetryClient.java | 7 +--- .../datadog/telemetry/TelemetrySystem.java | 5 ++- .../telemetry/TelemetryClientTest.groovy | 13 +++++- .../TelemetrySystemSpecification.groovy | 2 +- .../java/datadog/flare/TracerFlarePoller.java | 2 +- 22 files changed, 93 insertions(+), 55 deletions(-) diff --git a/communication/src/main/java/datadog/communication/BackendApiFactory.java b/communication/src/main/java/datadog/communication/BackendApiFactory.java index 253b7a5ecad..39124ae1162 100644 --- a/communication/src/main/java/datadog/communication/BackendApiFactory.java +++ b/communication/src/main/java/datadog/communication/BackendApiFactory.java @@ -3,13 +3,11 @@ import datadog.communication.ddagent.DDAgentFeaturesDiscovery; import datadog.communication.ddagent.SharedCommunicationObjects; import datadog.communication.http.HttpRetryPolicy; -import datadog.communication.http.OkHttpUtils; import datadog.trace.api.Config; import datadog.trace.api.intake.Intake; import datadog.trace.util.throwable.FatalAgentMisconfigurationError; import javax.annotation.Nullable; import okhttp3.HttpUrl; -import okhttp3.OkHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,10 +34,13 @@ public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommuni "Agentless mode is enabled and api key is not set. Please set application key"); } String traceId = config.getIdGenerationStrategy().generateTraceId().toString(); - OkHttpClient httpClient = - OkHttpUtils.buildHttpClient( - agentlessUrl, config.getCiVisibilityBackendApiTimeoutMillis()); - return new IntakeApi(agentlessUrl, apiKey, traceId, retryPolicyFactory, httpClient, true); + return new IntakeApi( + agentlessUrl, + apiKey, + traceId, + retryPolicyFactory, + sharedCommunicationObjects.getIntakeHttpClient(config), + true); } DDAgentFeaturesDiscovery featuresDiscovery = @@ -55,7 +56,7 @@ public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommuni evpProxyUrl, subdomain, retryPolicyFactory, - sharedCommunicationObjects.okHttpClient, + sharedCommunicationObjects.agentHttpClient, true); } diff --git a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java index 9cea9990cbf..01a0eb6704f 100644 --- a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java +++ b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java @@ -27,12 +27,24 @@ public class SharedCommunicationObjects { private final List pausedComponents = new ArrayList<>(); private volatile boolean paused; - public OkHttpClient okHttpClient; + /** + * HTTP client for making requests to Datadog agent. Depending on configuration, this client may + * use regular HTTP, UDS or named pipe. + */ + public OkHttpClient agentHttpClient; + public HttpUrl agentUrl; public Monitoring monitoring; private volatile DDAgentFeaturesDiscovery featuresDiscovery; private ConfigurationPoller configurationPoller; + /** + * HTTP client for making requests directly to Datadog backend. Unlike {@link #agentHttpClient}, + * this client is not configured to use UDS or named pipe, and will not force the use of + * clear-text HTTP. + */ + private volatile OkHttpClient intakeHttpClient; + public SharedCommunicationObjects() { this(false); } @@ -51,12 +63,15 @@ public void createRemaining(Config config) { throw new IllegalArgumentException("Bad agent URL: " + config.getAgentUrl()); } } - if (okHttpClient == null) { + if (agentHttpClient == null) { String unixDomainSocket = SocketUtils.discoverApmSocket(config); String namedPipe = config.getAgentNamedPipe(); - okHttpClient = + agentHttpClient = OkHttpUtils.buildHttpClient( - agentUrl, unixDomainSocket, namedPipe, getHttpClientTimeout(config)); + agentUrl != null && "http".equals(agentUrl.scheme()), + unixDomainSocket, + namedPipe, + getHttpClientTimeout(config)); } } @@ -130,7 +145,7 @@ private ConfigurationPoller createPoller(Config config) { configUrlSupplier = new RetryConfigUrlSupplier(this, config); } return new DefaultConfigurationPoller( - config, TRACER_VERSION, containerId, entityId, configUrlSupplier, okHttpClient); + config, TRACER_VERSION, containerId, entityId, configUrlSupplier, agentHttpClient); } // for testing @@ -146,7 +161,7 @@ public DDAgentFeaturesDiscovery featuresDiscovery(Config config) { createRemaining(config); ret = new DDAgentFeaturesDiscovery( - okHttpClient, + agentHttpClient, monitoring, agentUrl, config.isTraceAgentV05Enabled(), @@ -209,4 +224,19 @@ public String get() { return this.configUrl; } } + + public OkHttpClient getIntakeHttpClient(Config config) { + OkHttpClient intakeHttpClient = this.intakeHttpClient; + if (intakeHttpClient != null) { + return intakeHttpClient; + } + + synchronized (this) { + if (this.intakeHttpClient == null) { + this.intakeHttpClient = + OkHttpUtils.buildHttpClient(false, null, null, getHttpClientTimeout(config)); + } + return this.intakeHttpClient; + } + } } diff --git a/communication/src/main/java/datadog/communication/http/OkHttpUtils.java b/communication/src/main/java/datadog/communication/http/OkHttpUtils.java index 1e723728819..e7338b3a3eb 100644 --- a/communication/src/main/java/datadog/communication/http/OkHttpUtils.java +++ b/communication/src/main/java/datadog/communication/http/OkHttpUtils.java @@ -58,11 +58,11 @@ public final class OkHttpUtils { SystemProperties.getOrDefault("java.vm.vendor", "unknown"); public static OkHttpClient buildHttpClient(final HttpUrl url, final long timeoutMillis) { - return buildHttpClient(url, null, null, timeoutMillis); + return buildHttpClient(url != null && "http".equals(url.scheme()), null, null, timeoutMillis); } public static OkHttpClient buildHttpClient( - final HttpUrl url, + final boolean isHttp, final String unixDomainSocketPath, final String namedPipe, final long timeoutMillis) { @@ -70,7 +70,7 @@ public static OkHttpClient buildHttpClient( unixDomainSocketPath, namedPipe, null, - url, + isHttp, null, null, null, @@ -95,7 +95,7 @@ public static OkHttpClient buildHttpClient( discoverApmSocket(config), config.getAgentNamedPipe(), dispatcher, - url, + url != null && "http".equals(url.scheme()), retryOnConnectionFailure, maxRunningRequests, proxyHost, @@ -111,7 +111,7 @@ private static OkHttpClient buildHttpClient( final String unixDomainSocketPath, final String namedPipe, final Dispatcher dispatcher, - final HttpUrl url, + final boolean isHttp, final Boolean retryOnConnectionFailure, final Integer maxRunningRequests, final String proxyHost, @@ -151,7 +151,6 @@ private static OkHttpClient buildHttpClient( log.debug("Using NamedPipe as http transport"); } - boolean isHttp = url != null && "http".equals(url.scheme()); if (isHttp) { // force clear text when using http to avoid failures for JVMs without TLS builder.connectionSpecs(Collections.singletonList(ConnectionSpec.CLEARTEXT)); diff --git a/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy b/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy index 0584c32fdf6..bd03e0efd83 100644 --- a/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy +++ b/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy @@ -24,7 +24,7 @@ class SharedCommunicationsObjectsSpecification extends DDSpecification { 1 * config.agentTimeout >> 1 1 * config.agentUnixDomainSocket >> null sco.agentUrl as String == 'http://example.com/' - sco.okHttpClient != null + sco.agentHttpClient != null sco.monitoring.is(Monitoring.DISABLED) when: @@ -78,7 +78,7 @@ class SharedCommunicationsObjectsSpecification extends DDSpecification { DDAgentFeaturesDiscovery agentFeaturesDiscovery = Mock() sco.agentUrl = url - sco.okHttpClient = okHttpClient + sco.agentHttpClient = okHttpClient sco.monitoring = monitoring sco.featuresDiscovery = agentFeaturesDiscovery @@ -88,7 +88,7 @@ class SharedCommunicationsObjectsSpecification extends DDSpecification { then: 0 * _ sco.agentUrl.is(url) - sco.okHttpClient.is(okHttpClient) + sco.agentHttpClient.is(okHttpClient) sco.monitoring.is(monitoring) sco.featuresDiscovery.is(agentFeaturesDiscovery) } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java index 8b778a55ee1..6fa99d27fd3 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/CiVisibilityServices.java @@ -153,7 +153,7 @@ private static CiEnvironment buildCiEnvironment(Config config, SharedCommunicati CiEnvironment remoteEnvironment = new CiEnvironmentImpl( getRemoteEnvironment( - remoteEnvVarsProviderUrl, remoteEnvVarsProviderKey, sco.okHttpClient)); + remoteEnvVarsProviderUrl, remoteEnvVarsProviderKey, sco.agentHttpClient)); return new CompositeCiEnvironment(remoteEnvironment, localEnvironment); } else { return localEnvironment; diff --git a/dd-java-agent/appsec/src/jmh/java/datadog/appsec/benchmark/AppSecBenchmark.java b/dd-java-agent/appsec/src/jmh/java/datadog/appsec/benchmark/AppSecBenchmark.java index 4d12ce802d3..ee1b028672f 100644 --- a/dd-java-agent/appsec/src/jmh/java/datadog/appsec/benchmark/AppSecBenchmark.java +++ b/dd-java-agent/appsec/src/jmh/java/datadog/appsec/benchmark/AppSecBenchmark.java @@ -70,9 +70,9 @@ public void setUp() throws URISyntaxException { ss = gw.getSubscriptionService(RequestContextSlot.APPSEC); SharedCommunicationObjects sharedCommunicationObjects = new SharedCommunicationObjects(); sharedCommunicationObjects.monitoring = Monitoring.DISABLED; - sharedCommunicationObjects.okHttpClient = new StubOkHttpClient(); + sharedCommunicationObjects.agentHttpClient = new StubOkHttpClient(); sharedCommunicationObjects.setFeaturesDiscovery( - new StubDDAgentFeaturesDiscovery(sharedCommunicationObjects.okHttpClient)); + new StubDDAgentFeaturesDiscovery(sharedCommunicationObjects.agentHttpClient)); AppSecSystem.start(ss, sharedCommunicationObjects); uri = new URIDefaultDataAdapter(new URI("http://localhost:8080/test")); diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/AppSecSystemSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/AppSecSystemSpecification.groovy index 0f00d917100..96d70b90329 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/AppSecSystemSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/AppSecSystemSpecification.groovy @@ -182,7 +182,7 @@ class AppSecSystemSpecification extends DDSpecification { poller } } - sco.okHttpClient = Stub(OkHttpClient) + sco.agentHttpClient = Stub(OkHttpClient) sco.monitoring = Mock(Monitoring) sco.featuresDiscovery = Stub(DDAgentFeaturesDiscovery) sco diff --git a/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/InstrumentationSpecification.groovy b/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/InstrumentationSpecification.groovy index 4601b662430..2edd984c51b 100644 --- a/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/InstrumentationSpecification.groovy +++ b/dd-java-agent/instrumentation-testing/src/main/groovy/datadog/trace/agent/test/InstrumentationSpecification.groovy @@ -371,7 +371,7 @@ abstract class InstrumentationSpecification extends DDSpecification implements A // emit traces to the APM Test-Agent for Cross-Tracer Testing Trace Checks HttpUrl agentUrl = HttpUrl.get("http://" + agentHost + ":" + DEFAULT_TRACE_AGENT_PORT) - OkHttpClient client = buildHttpClient(agentUrl, null, null, TimeUnit.SECONDS.toMillis(DEFAULT_AGENT_TIMEOUT)) + OkHttpClient client = buildHttpClient(true, null, null, TimeUnit.SECONDS.toMillis(DEFAULT_AGENT_TIMEOUT)) DDAgentFeaturesDiscovery featureDiscovery = new DDAgentFeaturesDiscovery(client, Monitoring.DISABLED, agentUrl, Config.get().isTraceAgentV05Enabled(), Config.get().isTracerMetricsEnabled()) TEST_AGENT_API = new DDAgentApi(client, agentUrl, featureDiscovery, Monitoring.DISABLED, Config.get().isTracerMetricsEnabled()) TEST_AGENT_WRITER = DDAgentWriter.builder().agentApi(TEST_AGENT_API).build() diff --git a/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java b/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java index d2fd5e12a93..1a0cfd9e9bc 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/metrics/ConflatingMetricsAggregator.java @@ -113,7 +113,7 @@ public ConflatingMetricsAggregator( sharedCommunicationObjects.featuresDiscovery(config), healthMetrics, new OkHttpSink( - sharedCommunicationObjects.okHttpClient, + sharedCommunicationObjects.agentHttpClient, sharedCommunicationObjects.agentUrl.toString(), V6_METRICS_ENDPOINT, config.isTracerMetricsBufferingEnabled(), diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/DDAgentWriter.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/DDAgentWriter.java index 50b9aba2cdb..728df7a134f 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/DDAgentWriter.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/DDAgentWriter.java @@ -138,7 +138,7 @@ public DDAgentWriter build() { final HttpUrl agentUrl = HttpUrl.get("http://" + agentHost + ":" + traceAgentPort); final OkHttpClient client = null == featureDiscovery || null == agentApi - ? buildHttpClient(agentUrl, unixDomainSocket, namedPipe, timeoutMillis) + ? buildHttpClient(true, unixDomainSocket, namedPipe, timeoutMillis) : null; if (null == featureDiscovery) { featureDiscovery = diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java index 37ad215baec..9c7b2c3b08a 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java @@ -143,7 +143,7 @@ public static Writer createWriter( DDAgentApi ddAgentApi = new DDAgentApi( - commObjects.okHttpClient, + commObjects.agentHttpClient, commObjects.agentUrl, featuresDiscovery, commObjects.monitoring, @@ -202,7 +202,7 @@ private static RemoteApi createDDIntakeRemoteApi( if (useProxyApi) { return DDEvpProxyApi.builder() - .httpClient(commObjects.okHttpClient) + .httpClient(commObjects.agentHttpClient) .agentUrl(commObjects.agentUrl) .evpProxyEndpoint(featuresDiscovery.getEvpProxyEndpoint()) .trackType(trackType) @@ -224,6 +224,7 @@ private static RemoteApi createDDIntakeRemoteApi( } return DDIntakeApi.builder() .hostUrl(hostUrl) + .httpClient(commObjects.getIntakeHttpClient(config)) .apiKey(config.getApiKey()) .trackType(trackType) .build(); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java index 64efd7bda02..c86b9402081 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java @@ -75,7 +75,7 @@ public DefaultDataStreamsMonitoring( Supplier traceConfigSupplier) { this( new OkHttpSink( - sharedCommunicationObjects.okHttpClient, + sharedCommunicationObjects.agentHttpClient, sharedCommunicationObjects.agentUrl.toString(), V01_DATASTREAMS_ENDPOINT, false, diff --git a/dd-trace-core/src/test/groovy/datadog/trace/TracerConnectionReliabilityTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/TracerConnectionReliabilityTest.groovy index 96ef08b4a6e..5f0e62f48bf 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/TracerConnectionReliabilityTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/TracerConnectionReliabilityTest.groovy @@ -51,7 +51,7 @@ class TracerConnectionReliabilityTest extends DDSpecification { properties.put("trace.agent.port", Integer.toString(agentContainerPort)) def sharedCommunicationObjects = new SharedCommunicationObjects() sharedCommunicationObjects.agentUrl = HttpUrl.get("http://localhost:" + agentContainerPort) - sharedCommunicationObjects.okHttpClient = client + sharedCommunicationObjects.agentHttpClient = client def fixedFeaturesDiscovery = new FixedTraceEndpointFeaturesDiscovery(sharedCommunicationObjects) sharedCommunicationObjects.setFeaturesDiscovery(fixedFeaturesDiscovery) @@ -147,7 +147,7 @@ class TracerConnectionReliabilityTest extends DDSpecification { class FixedTraceEndpointFeaturesDiscovery extends DDAgentFeaturesDiscovery { FixedTraceEndpointFeaturesDiscovery(SharedCommunicationObjects objects) { - super(objects.okHttpClient, Monitoring.DISABLED, objects.agentUrl, false, false) + super(objects.agentHttpClient, Monitoring.DISABLED, objects.agentUrl, false, false) } @Override diff --git a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy index bf90db64ff8..b7b461b1db1 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/common/writer/WriterFactoryTest.groovy @@ -51,7 +51,7 @@ class WriterFactoryTest extends DDSpecification { // Create SharedCommunicationObjects with mocked HTTP client def sharedComm = new SharedCommunicationObjects() - sharedComm.okHttpClient = mockHttpClient + sharedComm.agentHttpClient = mockHttpClient sharedComm.agentUrl = HttpUrl.parse(config.agentUrl) sharedComm.createRemaining(config) @@ -127,7 +127,7 @@ class WriterFactoryTest extends DDSpecification { // Create SharedCommunicationObjects with mocked HTTP client def sharedComm = new SharedCommunicationObjects() - sharedComm.okHttpClient = mockHttpClient + sharedComm.agentHttpClient = mockHttpClient sharedComm.agentUrl = HttpUrl.parse(config.agentUrl) sharedComm.createRemaining(config) diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/CoreTracerTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/CoreTracerTest.groovy index ba781cf010c..7cc50cc0e9b 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/CoreTracerTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/CoreTracerTest.groovy @@ -325,7 +325,7 @@ class CoreTracerTest extends DDCoreSpecification { def key = ParsedConfigKey.parse("datadog/2/APM_TRACING/config_overrides/config") def poller = Mock(ConfigurationPoller) def sco = new SharedCommunicationObjects( - okHttpClient: Mock(OkHttpClient), + agentHttpClient: Mock(OkHttpClient), monitoring: Mock(Monitoring), agentUrl: HttpUrl.get('https://example.com'), featuresDiscovery: Mock(DDAgentFeaturesDiscovery), @@ -425,7 +425,7 @@ class CoreTracerTest extends DDCoreSpecification { def key = ParsedConfigKey.parse("datadog/2/APM_TRACING/config_overrides/config") def poller = Mock(ConfigurationPoller) def sco = new SharedCommunicationObjects( - okHttpClient: Mock(OkHttpClient), + agentHttpClient: Mock(OkHttpClient), monitoring: Mock(Monitoring), agentUrl: HttpUrl.get('https://example.com'), featuresDiscovery: Mock(DDAgentFeaturesDiscovery), @@ -479,7 +479,7 @@ class CoreTracerTest extends DDCoreSpecification { def key = ParsedConfigKey.parse("datadog/2/APM_TRACING/config_overrides/config") def poller = Mock(ConfigurationPoller) def sco = new SharedCommunicationObjects( - okHttpClient: Mock(OkHttpClient), + agentHttpClient: Mock(OkHttpClient), monitoring: Mock(Monitoring), agentUrl: HttpUrl.get('https://example.com'), featuresDiscovery: Mock(DDAgentFeaturesDiscovery), @@ -586,7 +586,7 @@ class CoreTracerTest extends DDCoreSpecification { def key = ParsedConfigKey.parse("datadog/2/APM_TRACING/config_overrides/config") def poller = Mock(ConfigurationPoller) def sco = new SharedCommunicationObjects( - okHttpClient: Mock(OkHttpClient), + agentHttpClient: Mock(OkHttpClient), monitoring: Mock(Monitoring), agentUrl: HttpUrl.get('https://example.com'), featuresDiscovery: Mock(DDAgentFeaturesDiscovery), diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/TracingConfigPollerTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/TracingConfigPollerTest.groovy index 63d70911f47..ff5b0ea4e25 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/TracingConfigPollerTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/TracingConfigPollerTest.groovy @@ -106,7 +106,7 @@ class TracingConfigPollerTest extends DDCoreSpecification { def serviceKey = ParsedConfigKey.parse("datadog/2/APM_TRACING/service_config/config") def poller = Mock(ConfigurationPoller) def sco = new SharedCommunicationObjects( - okHttpClient: Mock(OkHttpClient), + agentHttpClient: Mock(OkHttpClient), monitoring: Mock(Monitoring), agentUrl: HttpUrl.get('https://example.com'), featuresDiscovery: Mock(DDAgentFeaturesDiscovery), @@ -216,7 +216,7 @@ class TracingConfigPollerTest extends DDCoreSpecification { def orgConfig2Key = ParsedConfigKey.parse("datadog/2/APM_TRACING/org_config/config2") def poller = Mock(ConfigurationPoller) def sco = new SharedCommunicationObjects( - okHttpClient: Mock(OkHttpClient), + agentHttpClient: Mock(OkHttpClient), monitoring: Mock(Monitoring), agentUrl: HttpUrl.get('https://example.com'), featuresDiscovery: Mock(DDAgentFeaturesDiscovery), diff --git a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DataStreamsWritingTest.groovy b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DataStreamsWritingTest.groovy index 49e6c74639f..c3d67b653c0 100644 --- a/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DataStreamsWritingTest.groovy +++ b/dd-trace-core/src/test/groovy/datadog/trace/core/datastreams/DataStreamsWritingTest.groovy @@ -69,7 +69,7 @@ class DataStreamsWritingTest extends DDCoreSpecification { def sharedCommObjects = new SharedCommunicationObjects() sharedCommObjects.featuresDiscovery = features - sharedCommObjects.okHttpClient = testOkhttpClient + sharedCommObjects.agentHttpClient = testOkhttpClient sharedCommObjects.createRemaining(fakeConfig) def timeSource = new ControllableTimeSource() @@ -129,7 +129,7 @@ class DataStreamsWritingTest extends DDCoreSpecification { def sharedCommObjects = new SharedCommunicationObjects() sharedCommObjects.featuresDiscovery = features - sharedCommObjects.okHttpClient = testOkhttpClient + sharedCommObjects.agentHttpClient = testOkhttpClient sharedCommObjects.createRemaining(fakeConfig) def timeSource = new ControllableTimeSource() diff --git a/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java b/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java index e06e75ea0b3..e5de8ae525a 100644 --- a/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java +++ b/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java @@ -6,7 +6,6 @@ import datadog.trace.util.Strings; import java.io.IOException; import java.io.InterruptedIOException; -import java.util.concurrent.TimeUnit; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -30,7 +29,7 @@ public static TelemetryClient buildAgentClient( } public static TelemetryClient buildIntakeClient( - Config config, HttpRetryPolicy.Factory httpRetryPolicy) { + Config config, OkHttpClient okHttpClient, HttpRetryPolicy.Factory httpRetryPolicy) { String apiKey = config.getApiKey(); if (apiKey == null) { log.debug("Cannot create Telemetry Intake because DD_API_KEY unspecified."); @@ -46,9 +45,7 @@ public static TelemetryClient buildIntakeClient( return null; } - long timeoutMillis = TimeUnit.SECONDS.toMillis(config.getAgentTimeout()); - OkHttpClient httpClient = OkHttpUtils.buildHttpClient(url, timeoutMillis); - return new TelemetryClient(httpClient, httpRetryPolicy, url, apiKey); + return new TelemetryClient(okHttpClient, httpRetryPolicy, url, apiKey); } private static String buildIntakeTelemetryUrl(Config config) { diff --git a/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java b/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java index 9325899e75d..56c200e2a71 100644 --- a/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java +++ b/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java @@ -101,8 +101,9 @@ public static void startTelemetry( : HttpRetryPolicy.Factory.NEVER_RETRY; TelemetryClient agentClient = - TelemetryClient.buildAgentClient(sco.okHttpClient, sco.agentUrl, httpRetryPolicy); - TelemetryClient intakeClient = TelemetryClient.buildIntakeClient(config, httpRetryPolicy); + TelemetryClient.buildAgentClient(sco.agentHttpClient, sco.agentUrl, httpRetryPolicy); + TelemetryClient intakeClient = + TelemetryClient.buildIntakeClient(config, sco.getIntakeHttpClient(config), httpRetryPolicy); boolean useIntakeClientByDefault = config.isCiVisibilityEnabled() && config.isCiVisibilityAgentlessEnabled(); diff --git a/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy b/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy index 323bef8c131..a2be8576e9e 100644 --- a/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy +++ b/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy @@ -1,12 +1,15 @@ package datadog.telemetry import datadog.communication.http.HttpRetryPolicy +import datadog.communication.http.OkHttpUtils import datadog.telemetry.api.RequestType import datadog.trace.api.Config import okhttp3.HttpUrl import okhttp3.OkHttpClient import spock.lang.Specification +import java.util.concurrent.TimeUnit + class TelemetryClientTest extends Specification { def "Intake client uses correct URL for site #site"() { @@ -16,8 +19,11 @@ class TelemetryClientTest extends Specification { config.getAgentTimeout() >> 123 config.getSite() >> site + long timeoutMillis = TimeUnit.SECONDS.toMillis(config.getAgentTimeout()) + OkHttpClient httpClient = OkHttpUtils.buildHttpClient(false, null, null, timeoutMillis) + when: - def intakeClient = TelemetryClient.buildIntakeClient(config, HttpRetryPolicy.Factory.NEVER_RETRY) + def intakeClient = TelemetryClient.buildIntakeClient(config, httpClient, HttpRetryPolicy.Factory.NEVER_RETRY) then: intakeClient.getUrl().toString() == expectedUrl @@ -42,8 +48,11 @@ class TelemetryClientTest extends Specification { config.isCiVisibilityAgentlessEnabled() >> ciVisAgentlessEnabled config.getCiVisibilityAgentlessUrl() >> ciVisAgentlessUrl + long timeoutMillis = TimeUnit.SECONDS.toMillis(config.getAgentTimeout()) + OkHttpClient httpClient = OkHttpUtils.buildHttpClient(false, null, null, timeoutMillis) + when: - def intakeClient = TelemetryClient.buildIntakeClient(config, HttpRetryPolicy.Factory.NEVER_RETRY) + def intakeClient = TelemetryClient.buildIntakeClient(config, httpClient, HttpRetryPolicy.Factory.NEVER_RETRY) then: intakeClient.getUrl().toString() == expectedUrl diff --git a/telemetry/src/test/groovy/datadog/telemetry/TelemetrySystemSpecification.groovy b/telemetry/src/test/groovy/datadog/telemetry/TelemetrySystemSpecification.groovy index c4957e91822..69b3ac67bcc 100644 --- a/telemetry/src/test/groovy/datadog/telemetry/TelemetrySystemSpecification.groovy +++ b/telemetry/src/test/groovy/datadog/telemetry/TelemetrySystemSpecification.groovy @@ -64,7 +64,7 @@ class TelemetrySystemSpecification extends DDSpecification { private SharedCommunicationObjects sharedCommunicationObjects() { new SharedCommunicationObjects( - okHttpClient: Mock(OkHttpClient), + agentHttpClient: Mock(OkHttpClient), monitoring: Mock(Monitoring), agentUrl: HttpUrl.get('https://example.com'), featuresDiscovery: Mock(DDAgentFeaturesDiscovery) diff --git a/utils/flare-utils/src/main/java/datadog/flare/TracerFlarePoller.java b/utils/flare-utils/src/main/java/datadog/flare/TracerFlarePoller.java index e37d714fb9f..49755cf24d0 100644 --- a/utils/flare-utils/src/main/java/datadog/flare/TracerFlarePoller.java +++ b/utils/flare-utils/src/main/java/datadog/flare/TracerFlarePoller.java @@ -44,7 +44,7 @@ private void doStart(SharedCommunicationObjects sco) { Config config = Config.get(); stopPreparer = new Preparer().register(config, sco); stopSubmitter = new Submitter().register(config, sco); - tracerFlareService = new TracerFlareService(config, sco.okHttpClient, sco.agentUrl); + tracerFlareService = new TracerFlareService(config, sco.agentHttpClient, sco.agentUrl); } private void doStop() { From 54f5b5483b7d1962082fcb1e2abfeba2c6629227 Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Fri, 3 Oct 2025 14:01:35 +0200 Subject: [PATCH 2/7] Allow forcing clear-text HTTP for intake client --- .../communication/BackendApiFactory.java | 2 +- .../ddagent/SharedCommunicationObjects.java | 39 ++++++++++--------- .../trace/api/config/TracerConfig.java | 2 + .../trace/common/writer/WriterFactory.java | 2 +- .../main/java/datadog/trace/api/Config.java | 11 ++++++ .../datadog/telemetry/TelemetrySystem.java | 2 +- 6 files changed, 37 insertions(+), 21 deletions(-) diff --git a/communication/src/main/java/datadog/communication/BackendApiFactory.java b/communication/src/main/java/datadog/communication/BackendApiFactory.java index 39124ae1162..3ce78b88c22 100644 --- a/communication/src/main/java/datadog/communication/BackendApiFactory.java +++ b/communication/src/main/java/datadog/communication/BackendApiFactory.java @@ -39,7 +39,7 @@ public BackendApiFactory(Config config, SharedCommunicationObjects sharedCommuni apiKey, traceId, retryPolicyFactory, - sharedCommunicationObjects.getIntakeHttpClient(config), + sharedCommunicationObjects.getIntakeHttpClient(), true); } diff --git a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java index 01a0eb6704f..12b05835ff8 100644 --- a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java +++ b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java @@ -33,18 +33,19 @@ public class SharedCommunicationObjects { */ public OkHttpClient agentHttpClient; - public HttpUrl agentUrl; - public Monitoring monitoring; - private volatile DDAgentFeaturesDiscovery featuresDiscovery; - private ConfigurationPoller configurationPoller; - /** * HTTP client for making requests directly to Datadog backend. Unlike {@link #agentHttpClient}, - * this client is not configured to use UDS or named pipe, and will not force the use of - * clear-text HTTP. + * this client is not configured to use UDS or named pipe. */ private volatile OkHttpClient intakeHttpClient; + public long httpClientTimeout; + public boolean forceClearTextHttpForIntakeClient; + public HttpUrl agentUrl; + public Monitoring monitoring; + private volatile DDAgentFeaturesDiscovery featuresDiscovery; + private ConfigurationPoller configurationPoller; + public SharedCommunicationObjects() { this(false); } @@ -57,12 +58,21 @@ public void createRemaining(Config config) { if (monitoring == null) { monitoring = Monitoring.DISABLED; } + + httpClientTimeout = + !config.isCiVisibilityEnabled() + ? TimeUnit.SECONDS.toMillis(config.getAgentTimeout()) + : config.getCiVisibilityBackendApiTimeoutMillis(); + + forceClearTextHttpForIntakeClient = config.isForceClearTextHttpForIntakeClient(); + if (agentUrl == null) { agentUrl = parseAgentUrl(config); if (agentUrl == null) { throw new IllegalArgumentException("Bad agent URL: " + config.getAgentUrl()); } } + if (agentHttpClient == null) { String unixDomainSocket = SocketUtils.discoverApmSocket(config); String namedPipe = config.getAgentNamedPipe(); @@ -71,7 +81,7 @@ public void createRemaining(Config config) { agentUrl != null && "http".equals(agentUrl.scheme()), unixDomainSocket, namedPipe, - getHttpClientTimeout(config)); + httpClientTimeout); } } @@ -118,14 +128,6 @@ private static HttpUrl parseAgentUrl(Config config) { return HttpUrl.parse(agentUrl); } - private static long getHttpClientTimeout(Config config) { - if (!config.isCiVisibilityEnabled()) { - return TimeUnit.SECONDS.toMillis(config.getAgentTimeout()); - } else { - return config.getCiVisibilityBackendApiTimeoutMillis(); - } - } - public ConfigurationPoller configurationPoller(Config config) { if (configurationPoller == null && config.isRemoteConfigEnabled()) { configurationPoller = createPoller(config); @@ -225,7 +227,7 @@ public String get() { } } - public OkHttpClient getIntakeHttpClient(Config config) { + public OkHttpClient getIntakeHttpClient() { OkHttpClient intakeHttpClient = this.intakeHttpClient; if (intakeHttpClient != null) { return intakeHttpClient; @@ -234,7 +236,8 @@ public OkHttpClient getIntakeHttpClient(Config config) { synchronized (this) { if (this.intakeHttpClient == null) { this.intakeHttpClient = - OkHttpUtils.buildHttpClient(false, null, null, getHttpClientTimeout(config)); + OkHttpUtils.buildHttpClient( + forceClearTextHttpForIntakeClient, null, null, httpClientTimeout); } return this.intakeHttpClient; } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/TracerConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/TracerConfig.java index ae5d515cb62..d710d58ff29 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/TracerConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/TracerConfig.java @@ -26,6 +26,8 @@ public final class TracerConfig { public static final String AGENT_UNIX_DOMAIN_SOCKET = "trace.agent.unix.domain.socket"; public static final String AGENT_NAMED_PIPE = "trace.pipe.name"; public static final String AGENT_TIMEOUT = "trace.agent.timeout"; + public static final String FORCE_CLEAR_TEXT_HTTP_FOR_INTAKE_CLIENT = + "force.clear.text.http.for.intake.client"; public static final String PROXY_NO_PROXY = "proxy.no_proxy"; public static final String TRACE_AGENT_PATH = "trace.agent.path"; public static final String TRACE_AGENT_ARGS = "trace.agent.args"; diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java index 9c7b2c3b08a..3f5fec92562 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/WriterFactory.java @@ -224,7 +224,7 @@ private static RemoteApi createDDIntakeRemoteApi( } return DDIntakeApi.builder() .hostUrl(hostUrl) - .httpClient(commObjects.getIntakeHttpClient(config)) + .httpClient(commObjects.getIntakeHttpClient()) .apiKey(config.getApiKey()) .trackType(trackType) .build(); diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 92a7cb00e6c..6aff768ae5e 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -561,6 +561,7 @@ import static datadog.trace.api.config.TracerConfig.CLIENT_IP_ENABLED; import static datadog.trace.api.config.TracerConfig.CLOCK_SYNC_PERIOD; import static datadog.trace.api.config.TracerConfig.ENABLE_TRACE_AGENT_V05; +import static datadog.trace.api.config.TracerConfig.FORCE_CLEAR_TEXT_HTTP_FOR_INTAKE_CLIENT; import static datadog.trace.api.config.TracerConfig.HEADER_TAGS; import static datadog.trace.api.config.TracerConfig.HTTP_CLIENT_ERROR_STATUSES; import static datadog.trace.api.config.TracerConfig.HTTP_SERVER_ERROR_STATUSES; @@ -790,6 +791,9 @@ public static String getHostName() { private final String agentUnixDomainSocket; private final String agentNamedPipe; private final int agentTimeout; + /** Should be set to {@code true} when running in agentless mode in a JVM without TLS */ + private final boolean forceClearTextHttpForIntakeClient; + private final Set noProxyHosts; private final boolean prioritySamplingEnabled; private final String prioritySamplingForce; @@ -1468,6 +1472,9 @@ private Config(final ConfigProvider configProvider, final InstrumenterConfig ins agentTimeout = configProvider.getInteger(AGENT_TIMEOUT, DEFAULT_AGENT_TIMEOUT); + forceClearTextHttpForIntakeClient = + configProvider.getBoolean(FORCE_CLEAR_TEXT_HTTP_FOR_INTAKE_CLIENT, false); + // DD_PROXY_NO_PROXY is specified as a space-separated list of hosts noProxyHosts = tryMakeImmutableSet(configProvider.getSpacedList(PROXY_NO_PROXY)); @@ -2974,6 +2981,10 @@ public int getAgentTimeout() { return agentTimeout; } + public boolean isForceClearTextHttpForIntakeClient() { + return forceClearTextHttpForIntakeClient; + } + public Set getNoProxyHosts() { return noProxyHosts; } diff --git a/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java b/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java index 56c200e2a71..a37b7c9ca93 100644 --- a/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java +++ b/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java @@ -103,7 +103,7 @@ public static void startTelemetry( TelemetryClient agentClient = TelemetryClient.buildAgentClient(sco.agentHttpClient, sco.agentUrl, httpRetryPolicy); TelemetryClient intakeClient = - TelemetryClient.buildIntakeClient(config, sco.getIntakeHttpClient(config), httpRetryPolicy); + TelemetryClient.buildIntakeClient(config, sco.getIntakeHttpClient(), httpRetryPolicy); boolean useIntakeClientByDefault = config.isCiVisibilityEnabled() && config.isCiVisibilityAgentlessEnabled(); From 08e1fa990a5095344b0fda398a36f77783c7f643 Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Fri, 3 Oct 2025 14:55:21 +0200 Subject: [PATCH 3/7] Revert telemetry client update --- .../java/datadog/telemetry/TelemetryClient.java | 7 +++++-- .../java/datadog/telemetry/TelemetrySystem.java | 3 +-- .../datadog/telemetry/TelemetryClientTest.groovy | 13 ++----------- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java b/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java index e5de8ae525a..e06e75ea0b3 100644 --- a/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java +++ b/telemetry/src/main/java/datadog/telemetry/TelemetryClient.java @@ -6,6 +6,7 @@ import datadog.trace.util.Strings; import java.io.IOException; import java.io.InterruptedIOException; +import java.util.concurrent.TimeUnit; import okhttp3.HttpUrl; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -29,7 +30,7 @@ public static TelemetryClient buildAgentClient( } public static TelemetryClient buildIntakeClient( - Config config, OkHttpClient okHttpClient, HttpRetryPolicy.Factory httpRetryPolicy) { + Config config, HttpRetryPolicy.Factory httpRetryPolicy) { String apiKey = config.getApiKey(); if (apiKey == null) { log.debug("Cannot create Telemetry Intake because DD_API_KEY unspecified."); @@ -45,7 +46,9 @@ public static TelemetryClient buildIntakeClient( return null; } - return new TelemetryClient(okHttpClient, httpRetryPolicy, url, apiKey); + long timeoutMillis = TimeUnit.SECONDS.toMillis(config.getAgentTimeout()); + OkHttpClient httpClient = OkHttpUtils.buildHttpClient(url, timeoutMillis); + return new TelemetryClient(httpClient, httpRetryPolicy, url, apiKey); } private static String buildIntakeTelemetryUrl(Config config) { diff --git a/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java b/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java index a37b7c9ca93..8e4db7b5255 100644 --- a/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java +++ b/telemetry/src/main/java/datadog/telemetry/TelemetrySystem.java @@ -102,8 +102,7 @@ public static void startTelemetry( TelemetryClient agentClient = TelemetryClient.buildAgentClient(sco.agentHttpClient, sco.agentUrl, httpRetryPolicy); - TelemetryClient intakeClient = - TelemetryClient.buildIntakeClient(config, sco.getIntakeHttpClient(), httpRetryPolicy); + TelemetryClient intakeClient = TelemetryClient.buildIntakeClient(config, httpRetryPolicy); boolean useIntakeClientByDefault = config.isCiVisibilityEnabled() && config.isCiVisibilityAgentlessEnabled(); diff --git a/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy b/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy index a2be8576e9e..323bef8c131 100644 --- a/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy +++ b/telemetry/src/test/groovy/datadog/telemetry/TelemetryClientTest.groovy @@ -1,15 +1,12 @@ package datadog.telemetry import datadog.communication.http.HttpRetryPolicy -import datadog.communication.http.OkHttpUtils import datadog.telemetry.api.RequestType import datadog.trace.api.Config import okhttp3.HttpUrl import okhttp3.OkHttpClient import spock.lang.Specification -import java.util.concurrent.TimeUnit - class TelemetryClientTest extends Specification { def "Intake client uses correct URL for site #site"() { @@ -19,11 +16,8 @@ class TelemetryClientTest extends Specification { config.getAgentTimeout() >> 123 config.getSite() >> site - long timeoutMillis = TimeUnit.SECONDS.toMillis(config.getAgentTimeout()) - OkHttpClient httpClient = OkHttpUtils.buildHttpClient(false, null, null, timeoutMillis) - when: - def intakeClient = TelemetryClient.buildIntakeClient(config, httpClient, HttpRetryPolicy.Factory.NEVER_RETRY) + def intakeClient = TelemetryClient.buildIntakeClient(config, HttpRetryPolicy.Factory.NEVER_RETRY) then: intakeClient.getUrl().toString() == expectedUrl @@ -48,11 +42,8 @@ class TelemetryClientTest extends Specification { config.isCiVisibilityAgentlessEnabled() >> ciVisAgentlessEnabled config.getCiVisibilityAgentlessUrl() >> ciVisAgentlessUrl - long timeoutMillis = TimeUnit.SECONDS.toMillis(config.getAgentTimeout()) - OkHttpClient httpClient = OkHttpUtils.buildHttpClient(false, null, null, timeoutMillis) - when: - def intakeClient = TelemetryClient.buildIntakeClient(config, httpClient, HttpRetryPolicy.Factory.NEVER_RETRY) + def intakeClient = TelemetryClient.buildIntakeClient(config, HttpRetryPolicy.Factory.NEVER_RETRY) then: intakeClient.getUrl().toString() == expectedUrl From 6bca17636ff311b2766efa8d55c87087c0a04fc8 Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Fri, 3 Oct 2025 15:36:14 +0200 Subject: [PATCH 4/7] Fix integration tests --- .../src/traceAgentTest/groovy/DDApiIntegrationTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-trace-core/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy b/dd-trace-core/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy index 5aa3c5437e8..f6221a7168d 100644 --- a/dd-trace-core/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy +++ b/dd-trace-core/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy @@ -83,7 +83,7 @@ class DDApiIntegrationTest extends AbstractTraceAgentTest { api = new DDAgentApi(httpClient, agentUrl, discovery, monitoring, false) api.addResponseListener(responseListener) HttpUrl udsAgentUrl = HttpUrl.get(String.format("http://%s:%d", SOMEHOST, SOMEPORT)) - OkHttpClient udsClient = OkHttpUtils.buildHttpClient(udsAgentUrl, socketPath.toString(), null, 5000) + OkHttpClient udsClient = OkHttpUtils.buildHttpClient(true, socketPath.toString(), null, 5000) udsDiscovery = new DDAgentFeaturesDiscovery(udsClient, monitoring, agentUrl, enableV05, true) unixDomainSocketApi = new DDAgentApi(udsClient, udsAgentUrl, udsDiscovery, monitoring, false) unixDomainSocketApi.addResponseListener(responseListener) From d9bda25de2530ab6453b6c27ec26040a5c7f195b Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Fri, 3 Oct 2025 15:41:31 +0200 Subject: [PATCH 5/7] Fix unit tests --- .../ddagent/SharedCommunicationsObjectsSpecification.groovy | 3 +++ 1 file changed, 3 insertions(+) diff --git a/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy b/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy index bd03e0efd83..4c18f1fc84b 100644 --- a/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy +++ b/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy @@ -86,6 +86,9 @@ class SharedCommunicationsObjectsSpecification extends DDSpecification { sco.createRemaining(config) then: + 1 * config.isCiVisibilityEnabled() + 1 * config.getAgentTimeout() + 1 * config.isForceClearTextHttpForIntakeClient() 0 * _ sco.agentUrl.is(url) sco.agentHttpClient.is(okHttpClient) From 44a8642de1549d3ad81741d216778a7d6aa560b1 Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Fri, 3 Oct 2025 16:46:14 +0200 Subject: [PATCH 6/7] Add a unit test --- .../SharedCommunicationsObjectsSpecification.groovy | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy b/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy index 4c18f1fc84b..9795aca655c 100644 --- a/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy +++ b/communication/src/test/groovy/datadog/communication/ddagent/SharedCommunicationsObjectsSpecification.groovy @@ -127,4 +127,12 @@ class SharedCommunicationsObjectsSpecification extends DDSpecification { 1 * config.agentUnixDomainSocket >> null sco.agentUrl as String == 'http://[2600:1f18:19c0:bd07:d55b::17]:8126/' } + + void 'creates intake http client'() { + when: + def client = sco.getIntakeHttpClient() + + then: + client != null + } } From e49843a21e8fd43f7bb93c16dc58172235b07487 Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Mon, 6 Oct 2025 10:35:25 +0200 Subject: [PATCH 7/7] Address review comments --- .../ddagent/SharedCommunicationObjects.java | 17 +++++++---------- .../datadog/communication/http/OkHttpUtils.java | 8 ++++++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java index 12b05835ff8..3864ccbded1 100644 --- a/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java +++ b/communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java @@ -60,9 +60,9 @@ public void createRemaining(Config config) { } httpClientTimeout = - !config.isCiVisibilityEnabled() - ? TimeUnit.SECONDS.toMillis(config.getAgentTimeout()) - : config.getCiVisibilityBackendApiTimeoutMillis(); + config.isCiVisibilityEnabled() + ? config.getCiVisibilityBackendApiTimeoutMillis() + : TimeUnit.SECONDS.toMillis(config.getAgentTimeout()); forceClearTextHttpForIntakeClient = config.isForceClearTextHttpForIntakeClient(); @@ -78,10 +78,7 @@ public void createRemaining(Config config) { String namedPipe = config.getAgentNamedPipe(); agentHttpClient = OkHttpUtils.buildHttpClient( - agentUrl != null && "http".equals(agentUrl.scheme()), - unixDomainSocket, - namedPipe, - httpClientTimeout); + OkHttpUtils.isPlainHttp(agentUrl), unixDomainSocket, namedPipe, httpClientTimeout); } } @@ -228,9 +225,9 @@ public String get() { } public OkHttpClient getIntakeHttpClient() { - OkHttpClient intakeHttpClient = this.intakeHttpClient; - if (intakeHttpClient != null) { - return intakeHttpClient; + OkHttpClient client = this.intakeHttpClient; + if (client != null) { + return client; } synchronized (this) { diff --git a/communication/src/main/java/datadog/communication/http/OkHttpUtils.java b/communication/src/main/java/datadog/communication/http/OkHttpUtils.java index e7338b3a3eb..979a5cdfb3c 100644 --- a/communication/src/main/java/datadog/communication/http/OkHttpUtils.java +++ b/communication/src/main/java/datadog/communication/http/OkHttpUtils.java @@ -58,7 +58,7 @@ public final class OkHttpUtils { SystemProperties.getOrDefault("java.vm.vendor", "unknown"); public static OkHttpClient buildHttpClient(final HttpUrl url, final long timeoutMillis) { - return buildHttpClient(url != null && "http".equals(url.scheme()), null, null, timeoutMillis); + return buildHttpClient(isPlainHttp(url), null, null, timeoutMillis); } public static OkHttpClient buildHttpClient( @@ -95,7 +95,7 @@ public static OkHttpClient buildHttpClient( discoverApmSocket(config), config.getAgentNamedPipe(), dispatcher, - url != null && "http".equals(url.scheme()), + isPlainHttp(url), retryOnConnectionFailure, maxRunningRequests, proxyHost, @@ -392,4 +392,8 @@ private static void closeQuietly(Response response) { // ignore } } + + public static boolean isPlainHttp(final HttpUrl url) { + return url != null && "http".equalsIgnoreCase(url.scheme()); + } }