From f326662b0a6190237796e3e4973f493517a18c0d Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Thu, 16 Jul 2026 16:28:15 -0400 Subject: [PATCH 1/2] adding locale.root to toEnvVar --- .../test/InstrumentationSpecification.groovy | 2 +- .../datadog/trace/util/ConfigStrings.java | 17 ++------ .../datadog/trace/util/ConfigStringsTest.java | 43 +++++++++++++++++++ 3 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java 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 8970af5be26..951c2ecff3e 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 @@ -124,7 +124,7 @@ abstract class InstrumentationSpecification extends DDSpecification implements A StringBuilder ddEnvVars = new StringBuilder() for (Map.Entry entry : System.getProperties().entrySet()) { if (entry.getKey().toString().startsWith("dd.")) { - ddEnvVars.append(ConfigStrings.systemPropertyNameToEnvironmentVariableName(entry.getKey().toString())) + ddEnvVars.append(ConfigStrings.toEnvVar(entry.getKey().toString())) .append("=").append(entry.getValue()).append(",") } } diff --git a/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java b/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java index 137280ad539..2937e19a372 100644 --- a/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java +++ b/utils/config-utils/src/main/java/datadog/trace/util/ConfigStrings.java @@ -1,5 +1,6 @@ package datadog.trace.util; +import java.util.Locale; import javax.annotation.Nonnull; public final class ConfigStrings { @@ -7,11 +8,11 @@ public final class ConfigStrings { private ConfigStrings() {} public static String toEnvVar(String string) { - return string.replace('.', '_').replace('-', '_').toUpperCase(); + return string.replace('.', '_').replace('-', '_').toUpperCase(Locale.ROOT); } public static String toEnvVarLowerCase(String string) { - return string.replace('.', '_').replace('-', '_').toLowerCase(); + return string.replace('.', '_').replace('-', '_').toLowerCase(Locale.ROOT); } /** @@ -26,18 +27,6 @@ public static String propertyNameToEnvironmentVariableName(final String setting) return "DD_" + toEnvVar(setting); } - /** - * Converts the system property name, e.g. 'dd.service.name' into a public environment variable - * name, e.g. `DD_SERVICE_NAME`. - * - * @param setting The system property name, e.g. `dd.service.name` - * @return The public facing environment variable name - */ - @Nonnull - public static String systemPropertyNameToEnvironmentVariableName(final String setting) { - return setting.replace('.', '_').replace('-', '_').toUpperCase(); - } - /** * Converts the property name, e.g. 'service.name' into a public system property name, e.g. * `dd.service.name`. diff --git a/utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java b/utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java new file mode 100644 index 00000000000..5b2173f0363 --- /dev/null +++ b/utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java @@ -0,0 +1,43 @@ +package datadog.trace.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import java.util.Locale; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ConfigStringsTest { + + /** Dotted capital I (U+0130) that a Turkish-locale {@code toUpperCase()} produces from 'i'. */ + private static final char DOTTED_CAPITAL_I = 'İ'; + + private Locale previousDefault; + + @BeforeEach + void forceTurkishLocale() { + // Turkish is the locale where a locale-sensitive toUpperCase() maps 'i' -> 'İ' (U+0130) and + // toLowerCase() maps 'I' -> 'ı' (U+0131, dotless). That is exactly what corrupted the config + // telemetry payload. Forcing it as the default locale here proves the conversions are + // locale-independent (pinned to Locale.ROOT) rather than relying on the machine's locale. + previousDefault = Locale.getDefault(); + Locale.setDefault(new Locale("tr", "TR")); + } + + @AfterEach + void restoreLocale() { + Locale.setDefault(previousDefault); + } + + @Test + void toEnvVarUppercasesLowerIToAsciiIOnTurkishLocale() { + String result = ConfigStrings.toEnvVar("dd.profiling.i"); + + // Must be the plain ASCII 'I' (U+0049), not the Turkish dotted 'İ' (U+0130). + assertEquals("DD_PROFILING_I", result); + assertFalse( + result.indexOf(DOTTED_CAPITAL_I) >= 0, + "env var name must not contain the dotted capital I (U+0130)"); + } +} From d2e62e8c648e33cfae7987bbb5a7fb747748e948 Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Fri, 17 Jul 2026 10:16:07 -0400 Subject: [PATCH 2/2] force locale for individual test --- .../datadog/trace/util/ConfigStringsTest.java | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java b/utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java index 5b2173f0363..c8b5acb8dfd 100644 --- a/utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java +++ b/utils/config-utils/src/test/java/datadog/trace/util/ConfigStringsTest.java @@ -4,8 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import java.util.Locale; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; class ConfigStringsTest { @@ -13,31 +11,23 @@ class ConfigStringsTest { /** Dotted capital I (U+0130) that a Turkish-locale {@code toUpperCase()} produces from 'i'. */ private static final char DOTTED_CAPITAL_I = 'İ'; - private Locale previousDefault; - - @BeforeEach - void forceTurkishLocale() { - // Turkish is the locale where a locale-sensitive toUpperCase() maps 'i' -> 'İ' (U+0130) and - // toLowerCase() maps 'I' -> 'ı' (U+0131, dotless). That is exactly what corrupted the config - // telemetry payload. Forcing it as the default locale here proves the conversions are - // locale-independent (pinned to Locale.ROOT) rather than relying on the machine's locale. - previousDefault = Locale.getDefault(); - Locale.setDefault(new Locale("tr", "TR")); - } - - @AfterEach - void restoreLocale() { - Locale.setDefault(previousDefault); - } - @Test void toEnvVarUppercasesLowerIToAsciiIOnTurkishLocale() { - String result = ConfigStrings.toEnvVar("dd.profiling.i"); - - // Must be the plain ASCII 'I' (U+0049), not the Turkish dotted 'İ' (U+0130). - assertEquals("DD_PROFILING_I", result); - assertFalse( - result.indexOf(DOTTED_CAPITAL_I) >= 0, - "env var name must not contain the dotted capital I (U+0130)"); + // Turkish is the locale where a locale-sensitive toUpperCase() maps 'i' -> 'İ' + // Forcing it as the default locale here proves the conversions are + // locale-independent (pinned to Locale.ROOT) rather than relying on the machine's locale. + Locale previousDefault = Locale.getDefault(); + Locale.setDefault(new Locale("tr", "TR")); + try { + String result = ConfigStrings.toEnvVar("dd.profiling.i"); + + // Must be the plain ASCII 'I' (U+0049), not the Turkish dotted 'İ' (U+0130). + assertEquals("DD_PROFILING_I", result); + assertFalse( + result.indexOf(DOTTED_CAPITAL_I) >= 0, + "env var name must not contain the dotted capital I (U+0130)"); + } finally { + Locale.setDefault(previousDefault); + } } }