From 8c7fcba4d347479e12e511ef713d928c0e159ca3 Mon Sep 17 00:00:00 2001 From: "E. Lewis" Date: Fri, 23 Oct 2026 15:12:00 -0400 Subject: [PATCH] Read dd.dogstatsd.pipe.name for the default named pipe A JVM agent can set system properties after startup but not environment variables. serverless-compat-java will set dd.dogstatsd.pipe.name to a per-function pipe on Azure Functions shared plans, so a client built with default settings now uses it. Precedence: explicit builder settings, then the system property, then the existing DD_DOGSTATSD_URL, DD_DOGSTATSD_PIPE_NAME and DD_AGENT_HOST environment variables. The property pipe uses the same channel as every other named pipe. Since #345 that channel opens on the first write, so a client built before its pipe exists doesn't fail build(). SVLS-8246 --- .../statsd/NonBlockingStatsDClient.java | 1 + .../NonBlockingStatsDClientBuilder.java | 7 +++ .../timgroup/statsd/BuilderAddressTest.java | 55 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java index 2cb8a004..b10b51a6 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClient.java @@ -59,6 +59,7 @@ public class NonBlockingStatsDClient implements StatsDClient { public static final String DD_DOGSTATSD_PORT_ENV_VAR = "DD_DOGSTATSD_PORT"; public static final String DD_AGENT_HOST_ENV_VAR = "DD_AGENT_HOST"; public static final String DD_NAMED_PIPE_ENV_VAR = "DD_DOGSTATSD_PIPE_NAME"; + static final String DD_NAMED_PIPE_SYSTEM_PROPERTY = "dd.dogstatsd.pipe.name"; public static final String DD_ENTITY_ID_ENV_VAR = "DD_ENTITY_ID"; private static final String ENTITY_ID_TAG_NAME = "dd.internal.entity_id"; public static final String ORIGIN_DETECTION_ENABLED_ENV_VAR = "DD_ORIGIN_DETECTION_ENABLED"; diff --git a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClientBuilder.java b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClientBuilder.java index cfef457d..b625e9e8 100644 --- a/src/main/java/com/timgroup/statsd/NonBlockingStatsDClientBuilder.java +++ b/src/main/java/com/timgroup/statsd/NonBlockingStatsDClientBuilder.java @@ -431,6 +431,13 @@ private Callable getAddressLookup() { return staticAddress(hostname, port); } + // Next, try the system property, which can be set after the JVM has started. + String namedPipeFromProperty = + System.getProperty(NonBlockingStatsDClient.DD_NAMED_PIPE_SYSTEM_PROPERTY); + if (namedPipeFromProperty != null) { + return staticNamedPipeResolution(namedPipeFromProperty); + } + // Next, try various environment variables. String url = env.get(NonBlockingStatsDClient.DD_DOGSTATSD_URL_ENV_VAR); if (url != null) { diff --git a/src/test/java/com/timgroup/statsd/BuilderAddressTest.java b/src/test/java/com/timgroup/statsd/BuilderAddressTest.java index ea344be5..5d799794 100644 --- a/src/test/java/com/timgroup/statsd/BuilderAddressTest.java +++ b/src/test/java/com/timgroup/statsd/BuilderAddressTest.java @@ -9,7 +9,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.Callable; import jnr.unixsocket.UnixSocketAddress; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -196,6 +198,11 @@ public void set() { set(NonBlockingStatsDClient.DD_NAMED_PIPE_ENV_VAR, pipe); } + @After + public void clearNamedPipeSystemProperty() { + System.clearProperty(NonBlockingStatsDClient.DD_NAMED_PIPE_SYSTEM_PROPERTY); + } + void set(String name, String val) { if (val != null) { env.put(name, val); @@ -245,4 +252,52 @@ public void address_resolution() throws Exception { .resolve(); assertEquals(new NamedPipeSocketAddress("ook"), b.addressLookup.call()); } + + @Test(timeout = 5000L) + public void system_property_named_pipe_resolution() throws Exception { + System.setProperty(NonBlockingStatsDClient.DD_NAMED_PIPE_SYSTEM_PROPERTY, "sysprop"); + NonBlockingStatsDClientBuilder b; + + // Default configuration uses the system property regardless of environment variables. + b = new NonBlockingStatsDClientBuilder().withEnvironmentVariables(env).resolve(); + assertEquals(new NamedPipeSocketAddress("sysprop"), b.addressLookup.call()); + assertEquals(b.addressLookup, b.telemetryAddressLookup); + + // Explicit configuration is used regardless of the system property. + b = + new NonBlockingStatsDClientBuilder() + .withEnvironmentVariables(env) + .hostname("2.2.2.2") + .port(2222) + .resolve(); + assertEquals(new InetSocketAddress("2.2.2.2", 2222), b.addressLookup.call()); + + b = + new NonBlockingStatsDClientBuilder() + .withEnvironmentVariables(env) + .namedPipe("ook") + .resolve(); + assertEquals(new NamedPipeSocketAddress("ook"), b.addressLookup.call()); + + final SocketAddress explicit = new InetSocketAddress("3.3.3.3", 3333); + b = + new NonBlockingStatsDClientBuilder() + .withEnvironmentVariables(env) + .addressLookup( + new Callable() { + @Override + public SocketAddress call() { + return explicit; + } + }) + .resolve(); + assertEquals(explicit, b.addressLookup.call()); + + b = + new NonBlockingStatsDClientBuilder() + .withEnvironmentVariables(env) + .address("udp://4.4.4.4:4444") + .resolve(); + assertEquals(new InetSocketAddress("4.4.4.4", 4444), b.addressLookup.call()); + } }