Skip to content

[SVLS-8245] Give each Windows Azure Function its own named pipes - #43

Draft
Lewis-E wants to merge 6 commits into
mainfrom
lewis/SVLS-9467/java-pipe-names
Draft

Lewis-E wants to merge 6 commits into
mainfrom
lewis/SVLS-9467/java-pipe-names

Conversation

@Lewis-E

@Lewis-E Lewis-E commented Oct 15, 2026 •

Copy link
Copy Markdown

What does this PR do?

On Windows Azure Functions, the compat agent now gives each function app its own trace and DogStatsD named pipes, as the .NET compatibility layer has done since v1.5.0. In premain it hands the chosen names to dd-java-agent as the dd.trace.pipe.name and dd.dogstatsd.pipe.name system properties. The binary gets the same names as DD_APM_WINDOWS_PIPE_NAME and DD_DOGSTATSD_WINDOWS_PIPE_NAME.

NamedPipeNames follows the .NET CompatibilityLayer order for each pipe:

  1. DD_APM_WINDOWS_PIPE_NAME / DD_DOGSTATSD_WINDOWS_PIPE_NAME, used as written.
  2. A name the customer already set for the tracer: -Ddd.trace.pipe.name / -Ddd.dogstatsd.pipe.name, else DD_TRACE_PIPE_NAME / DD_DOGSTATSD_PIPE_NAME.
  3. A generated dd_trace_<guid> / dd_dogstatsd_<guid>.

It logs a warning when a customer-set name differs from the *_WINDOWS_PIPE_NAME value, and when a name is longer than 256 characters.

Pipes turn on only when the dd-java-agent in the JVM is new enough. TracerVersionGate finds the tracer among the -javaagent options by its manifest Premain-Class (datadog.trace.bootstrap.AgentPreCheck), so a renamed jar still counts. It compares the major.minor.patch of the tracer's Implementation-Version and ignores suffixes such as -SNAPSHOT. If the tracer is older, missing, or unreadable, the agent logs why at INFO and doesn't add pipe settings anywhere. Inherited environment variables stay as they are. Those apps keep today's TCP 8126 and UDP 8125 behavior, and pipe settings a customer configured by hand behave as they do today.

Motivation

SVLS-9467 / SVLS-8245. Java function apps that share an Elastic Premium or Dedicated plan also share instances. Their binaries collide on one pipe name or port. Shared TCP isn't a fallback on Windows, because the Azure sandbox only allows connections to localhost listeners in the function's own app. A tracer whose binary lost the race for 8126 gets Permission denied. Per-function pipes fixed this for .NET (datadog-serverless-compat-dotnet#20) and Node (datadog-serverless-compat-js#46). Java uses system properties instead of environment variables because a JVM can't change its own environment after it starts, and dd-trace-java's Config already reads dd.*.pipe.name properties ahead of environment variables.

The gate exists because no released dd-trace-java can use a pipe. Trace upload hangs forever on the tracer's shared pipe socket, and the tracer's StatsD client throws a NullPointerException whenever it has a pipe name. The fixes for both are in DataDog/dd-trace-java#12898.

Additional Notes

This can't merge until two releases exist:

  1. A datadog-serverless-compat binary release with serverless-components#181. That change keeps the binary's DogStatsD listening on UDP 8125 next to the pipe. Without it, customer java-dogstatsd-client code that sends to localhost:8125 loses its metrics.
  2. The first dd-trace-java release with the named-pipe fixes above.

TracerVersionGate.MINIMUM_TRACER_VERSION is 1.68.0, a placeholder for that release. It's the next unreleased version on dd-trace-java master: master's latest tag is v1.67.0 (v1.67.1 sits on a release branch), and dd-trace-java's version plugin bumps the minor for untagged commits, so master builds report 1.68.0-SNAPSHOT. The constant moves to the actual release before this merges. If the fixes miss 1.68.0, a 1.68.x tracer without them would pass the gate as written.

Design choices and known gaps:

  • The trace override reads DD_APM_WINDOWS_PIPE_NAME, the variable the binary reads. .NET's CompatibilityLayer reads DD_TRACE_WINDOWS_PIPE_NAME for that step.
  • When a customer sets both -Ddd.trace.pipe.name and DD_TRACE_PIPE_NAME, the agent uses the JVM option, matching dd-trace-java's own config order. DogStatsD names follow the same order.
  • The agent still uses a name over 256 characters after warning about it.
  • The gate reads -javaagent options from RuntimeMXBean.getInputArguments(), and only on Windows Azure Functions. dd-trace-java avoids ManagementFactory in its own premain because on some JDKs it loads java.util.logging.LogManager early, which breaks custom log managers. I don't know yet whether any Azure Functions Java app depends on a custom JVM-wide log manager, so I didn't copy dd-trace-java's reflection workaround.
  • An app with compat-java but no dd-java-agent doesn't get pipes. Its custom metrics stay on shared UDP 8125, as in .NET.
  • Customer clients built with java-dogstatsd-client defaults ignore dd.dogstatsd.pipe.name until the client change for SVLS-8246 is in a client release.

Describe how to test/QA your changes

mvn test runs 53 tests, 37 of them new:

  • NamedPipeNamesTest covers the name order, JVM options beating environment variables, empty values, generated names, and both warnings.
  • TracerVersionGateTest checks that the minimum, later versions, and dev builds of the minimum (1.68.0-SNAPSHOT, 1.68.0-105-gefa6bd64) pass. Older, missing, non-jar, unversioned, and unparseable tracers fail. One test renames the tracer jar to prove the gate matches on Premain-Class. The tests write real jars with manifests to a temp directory.

I also ran the gate in a JVM started with this agent and a real dd-java-agent-1.59.0.jar as -javaagent options. It skipped the compat jar, found the tracer, and reported 1.59.0 as older than 1.68.0. The premain wiring has no unit test. The planned end-to-end run on shared EP2 and P1V3 plans in serverless-compat-self-monitoring covers it, with dev builds of the binary, this agent, and dd-trace-java. That run hasn't happened yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant