diff --git a/.agents/skills/perf-review/references/guide.md b/.agents/skills/perf-review/references/guide.md index 3c2b9aaf721..4f22a69c31c 100644 --- a/.agents/skills/perf-review/references/guide.md +++ b/.agents/skills/perf-review/references/guide.md @@ -128,7 +128,15 @@ every call. Fix: `static final Pattern`. **`String.format` / format-string parsing.** Re-parses and allocates per call. Fix: direct concatenation, or pre-compute the result. Also watch for locale-dependent formatting crossing the -wire — a correctness issue on top of the perf one. +wire - a correctness issue on top of the perf one. + +**Explicit locales and charsets.** The shared [forbidden-apis ban list](../../../../gradle/forbiddenApiFilters/main.txt) +rejects JDK calls that use an implicit locale or charset. Use `Locale.ROOT` for identifiers and +machine-readable formatting, and the protocol's charset (usually `StandardCharsets.UTF_8`) for +byte conversions. Use `Strings.format(...)` where `internal-api` is already a dependency; it applies +`Locale.ROOT`. For intentional JVM defaults, use an explicit default or put `@SuppressForbidden` +on the smallest scope and explain why in a comment. Passing a locale still leaves `String.format` +with the parsing and allocation cost described above, including through `Strings.format(...)`. **`Config.get()` per call.** Walks a config-resolution chain; not a free read. Fix: hoist to a `static final` field at class initialization. This is the single most recurring DBM finding — diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ea7d895e36..dd002f748a4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,6 +91,19 @@ Wildcard imports (`import x.*` or `import static x.*`) are disallowed — see th * Switch to `IntelliJ IDEA CE 2021.2.3`. +## Explicit locales and charsets + +The shared [forbidden-apis ban list](gradle/forbiddenApiFilters/main.txt) requires explicit +locales and charsets in checked source sets. Use `Locale.ROOT` for identifiers and +machine-readable formatting. Modules that already depend on `internal-api` can use `Strings.format(...)`, +which applies `Locale.ROOT`. Use the protocol's charset, usually `StandardCharsets.UTF_8`, +for byte conversions. + +When a JVM default is intentional, pass `Locale.getDefault(...)` or `Charset.defaultCharset()` +explicitly and explain the reason. If the API has no suitable explicit overload, annotate the +smallest enclosing method or constructor with `@SuppressForbidden` and add a comment explaining +why it must use the default. The annotation is a compile-only dependency supplied by the convention. + ## Pull request guidelines ### Draft first diff --git a/buildSrc/src/test/kotlin/datadog/gradle/plugin/quality/ForbiddenApisConventionPluginTest.kt b/buildSrc/src/test/kotlin/datadog/gradle/plugin/quality/ForbiddenApisConventionPluginTest.kt index fef6bd17de4..48dc49a862e 100644 --- a/buildSrc/src/test/kotlin/datadog/gradle/plugin/quality/ForbiddenApisConventionPluginTest.kt +++ b/buildSrc/src/test/kotlin/datadog/gradle/plugin/quality/ForbiddenApisConventionPluginTest.kt @@ -113,6 +113,100 @@ class ForbiddenApisConventionPluginTest : GradleFixture() { .describedAs(result.output).isEqualTo(TaskOutcome.SUCCESS) } + @Test + fun `requires explicit locales and charsets and permits justified defaults`() { + writeFile("gradle/forbiddenApiFilters/main.txt", File("../gradle/forbiddenApiFilters/main.txt").readText()) + writeRootProject( + """ + plugins { + id("dd-trace-java.conventions.forbidden-apis") + } + repositories { + mavenCentral() + } + """ + ) + val implicit = """ + import java.io.InputStream; + import java.io.InputStreamReader; + import java.io.OutputStream; + import java.io.OutputStreamWriter; + import java.text.NumberFormat; + import de.thetaphi.forbiddenapis.SuppressForbidden; + + public class Example { + public void defaults(byte[] bytes, InputStream input, OutputStream output) throws Exception { + "IDENTIFIER".toLowerCase(); + "identifier".toUpperCase(); + String.format("%d", 123); + "text".getBytes(); + new String(bytes); + new String(bytes, 0, bytes.length); + new InputStreamReader(input); + new OutputStreamWriter(output); + NumberFormat.getIntegerInstance(); + } + } + """ + writeJavaSource("Example", implicit) + + val failed = run("check", expectFailure = true) + + assertThat(failed.task(":forbiddenApisMain")?.outcome) + .describedAs(failed.output).isEqualTo(TaskOutcome.FAILED) + assertThat(failed.output).contains( + "java.lang.String#toLowerCase()", + "java.lang.String#toUpperCase()", + "java.lang.String#format(java.lang.String,java.lang.Object[])", + "java.lang.String#getBytes()", + "java.lang.String#(byte[])", + "java.lang.String#(byte[],int,int)", + "java.io.InputStreamReader#(java.io.InputStream)", + "java.io.OutputStreamWriter#(java.io.OutputStream)", + "java.text.NumberFormat#getIntegerInstance()" + ) + + writeJavaSource( + "Example", + """ + import java.io.InputStream; + import java.io.InputStreamReader; + import java.io.OutputStream; + import java.io.OutputStreamWriter; + import java.nio.charset.StandardCharsets; + import java.text.NumberFormat; + import java.util.Locale; + + public class Example { + public void explicit(byte[] bytes, InputStream input, OutputStream output) throws Exception { + "IDENTIFIER".toLowerCase(Locale.ROOT); + "identifier".toUpperCase(Locale.ROOT); + String.format(Locale.ROOT, "%d", 123); + "text".getBytes(StandardCharsets.UTF_8); + new String(bytes, StandardCharsets.UTF_8); + new String(bytes, 0, bytes.length, StandardCharsets.UTF_8); + new InputStreamReader(input, StandardCharsets.UTF_8); + new OutputStreamWriter(output, StandardCharsets.UTF_8); + NumberFormat.getIntegerInstance(Locale.ROOT); + Integer.toString(123); + Long.toString(123L); + } + } + """ + ) + val explicit = run("check") + assertThat(explicit.task(":forbiddenApisMain")?.outcome) + .describedAs(explicit.output).isEqualTo(TaskOutcome.SUCCESS) + + writeJavaSource("Example", implicit.replace( + "public void defaults", + "// Exercise the JVM defaults deliberately.\n @SuppressForbidden\n public void defaults" + )) + val suppressed = run("check") + assertThat(suppressed.task(":forbiddenApisMain")?.outcome) + .describedAs(suppressed.output).isEqualTo(TaskOutcome.SUCCESS) + } + @Test fun `fails check on a forbidden call and allows compile-only suppression`() { writeRootProject( diff --git a/components/environment/src/main/java/datadog/environment/JavaVirtualMachine.java b/components/environment/src/main/java/datadog/environment/JavaVirtualMachine.java index d6fe120c98b..e9ffae6f47f 100644 --- a/components/environment/src/main/java/datadog/environment/JavaVirtualMachine.java +++ b/components/environment/src/main/java/datadog/environment/JavaVirtualMachine.java @@ -122,7 +122,7 @@ public static boolean isZulu8() { } public static boolean isGraalVM() { - return runtime.vendorVersion.toLowerCase().contains("graalvm"); + return runtime.vendorVersion.toLowerCase(Locale.ROOT).contains("graalvm"); } public static String getLangVersion() { diff --git a/components/environment/src/main/java/datadog/environment/OperatingSystem.java b/components/environment/src/main/java/datadog/environment/OperatingSystem.java index 7e64e6bdb33..edee1810f29 100644 --- a/components/environment/src/main/java/datadog/environment/OperatingSystem.java +++ b/components/environment/src/main/java/datadog/environment/OperatingSystem.java @@ -6,9 +6,11 @@ import static java.util.Locale.ROOT; import java.io.BufferedReader; -import java.io.FileReader; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -88,7 +90,10 @@ public static boolean isMusl() { } private static boolean isMuslProcSelfMaps() throws IOException { - try (BufferedReader reader = new BufferedReader(new FileReader("/proc/self/maps"))) { + try (BufferedReader reader = + new BufferedReader( + new InputStreamReader( + new FileInputStream("/proc/self/maps"), StandardCharsets.ISO_8859_1))) { String line; while ((line = reader.readLine()) != null) { if (line.contains("-musl-")) { diff --git a/components/json/src/main/java/datadog/json/JsonReader.java b/components/json/src/main/java/datadog/json/JsonReader.java index 771617cf0a2..f31cf595d2d 100644 --- a/components/json/src/main/java/datadog/json/JsonReader.java +++ b/components/json/src/main/java/datadog/json/JsonReader.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; /** @@ -490,22 +491,33 @@ private String readLiteral(int length) throws IOException { private IOException unexpectedSyntaxError(String expected, String found) { return new IOException( String.format( + Locale.ROOT, "Syntax error at line %d, position %d: expected %s but found '%s'", - this.lineNumber, this.linePosition, expected, found)); + this.lineNumber, + this.linePosition, + expected, + found)); } private IOException unexpectedSyntaxError(String expected, char found) { return new IOException( String.format( + Locale.ROOT, "Syntax error at line %d, position %d: expected %s but found '%s'", - this.lineNumber, this.linePosition, expected, found)); + this.lineNumber, + this.linePosition, + expected, + found)); } private IOException syntaxError(String message) { return new IOException( String.format( + Locale.ROOT, "Syntax error at line %d, position %d: %s", - this.lineNumber, this.linePosition, message)); + this.lineNumber, + this.linePosition, + message)); } @Override diff --git a/dd-java-agent/agent-aiguard/src/main/java/com/datadog/aiguard/AIGuardInternal.java b/dd-java-agent/agent-aiguard/src/main/java/com/datadog/aiguard/AIGuardInternal.java index 735c7108cc8..2710d288f85 100644 --- a/dd-java-agent/agent-aiguard/src/main/java/com/datadog/aiguard/AIGuardInternal.java +++ b/dd-java-agent/agent-aiguard/src/main/java/com/datadog/aiguard/AIGuardInternal.java @@ -34,6 +34,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.ClientIpAddressData; import datadog.trace.bootstrap.instrumentation.api.Tags; +import datadog.trace.util.Strings; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Type; @@ -107,7 +108,7 @@ public static void install() { } String endpoint = config.getAiGuardEndpoint(); if (isBlank(endpoint)) { - endpoint = String.format("https://app.%s/api/v2/ai-guard", config.getSite()); + endpoint = Strings.format("https://app.%s/api/v2/ai-guard", config.getSite()); } final Map headers = mapOf( diff --git a/dd-java-agent/agent-bootstrap/src/jmh/java/datadog/trace/bootstrap/instrumentation/buffer/InjectingPipeOutputStreamBenchmark.java b/dd-java-agent/agent-bootstrap/src/jmh/java/datadog/trace/bootstrap/instrumentation/buffer/InjectingPipeOutputStreamBenchmark.java index 8f52f13ee86..0ac8cd9a63b 100644 --- a/dd-java-agent/agent-bootstrap/src/jmh/java/datadog/trace/bootstrap/instrumentation/buffer/InjectingPipeOutputStreamBenchmark.java +++ b/dd-java-agent/agent-bootstrap/src/jmh/java/datadog/trace/bootstrap/instrumentation/buffer/InjectingPipeOutputStreamBenchmark.java @@ -6,6 +6,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -51,14 +52,18 @@ public class InjectingPipeOutputStreamBenchmark { public void withPipe() throws Exception { try (final PrintWriter out = new PrintWriter( - new InjectingPipeOutputStream(new ByteArrayOutputStream(), marker, content))) { + new OutputStreamWriter( + new InjectingPipeOutputStream(new ByteArrayOutputStream(), marker, content), + StandardCharsets.UTF_8))) { htmlContent.forEach(out::println); } } @Benchmark public void withoutPipe() throws Exception { - try (final PrintWriter out = new PrintWriter(new ByteArrayOutputStream())) { + try (final PrintWriter out = + new PrintWriter( + new OutputStreamWriter(new ByteArrayOutputStream(), StandardCharsets.UTF_8))) { htmlContent.forEach(out::println); } } diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/benchmark/StaticEventLogger.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/benchmark/StaticEventLogger.java index 2d73624e9f6..e8e6490df05 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/benchmark/StaticEventLogger.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/benchmark/StaticEventLogger.java @@ -4,9 +4,10 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.Objects; import org.slf4j.Logger; @@ -30,7 +31,10 @@ public class StaticEventLogger { String fileName = dir + "startup_" + System.currentTimeMillis() + ".csv"; try { - writer = new BufferedWriter(new FileWriter(fileName), 32768); + writer = + new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), + 32768); writer.write("Event,State,Timestamp"); writer.newLine(); } catch (IOException e) { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AppVeyorInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AppVeyorInfo.java index f8bc31dd090..f1d8eb4a624 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AppVeyorInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AppVeyorInfo.java @@ -65,7 +65,7 @@ private static String getCommitMessage(String messageSubject, String messageBody if (messageBody == null) { return messageSubject; } - return String.format("%s%n%s", messageSubject, messageBody); + return Strings.format("%s%n%s", messageSubject, messageBody); } @Override @@ -126,13 +126,13 @@ private String buildGitCommit() { private String buildGitRepositoryUrl(final String repoProvider, final String repoName) { if ("github".equals(repoProvider) && (repoName != null && !repoName.isEmpty())) { - return String.format("https://github.com/%s.git", repoName); + return Strings.format("https://github.com/%s.git", repoName); } return null; } private String buildPipelineUrl(final String repoName, final String buildId) { - return String.format("https://ci.appveyor.com/project/%s/builds/%s", repoName, buildId); + return Strings.format("https://ci.appveyor.com/project/%s/builds/%s", repoName, buildId); } private PersonInfo buildGitCommitAuthor() { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AzurePipelinesInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AzurePipelinesInfo.java index 11d3ebc65e3..bde42f8e336 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AzurePipelinesInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/AzurePipelinesInfo.java @@ -11,6 +11,7 @@ import datadog.trace.api.git.GitInfo; import datadog.trace.api.git.PersonInfo; import datadog.trace.civisibility.ci.env.CiEnvironment; +import datadog.trace.util.Strings; import javax.annotation.Nonnull; class AzurePipelinesInfo implements CIProviderInfo { @@ -144,12 +145,12 @@ private String buildCiJobUrl( final String buildId, final String jobId, final String taskId) { - return String.format( + return Strings.format( "%s%s/_build/results?buildId=%s&view=logs&j=%s&t=%s", uri, project, buildId, jobId, taskId); } private String buildCiPipelineUrl(final String uri, final String project, final String buildId) { - return String.format("%s%s/_build/results?buildId=%s", uri, project, buildId); + return Strings.format("%s%s/_build/results?buildId=%s", uri, project, buildId); } private PersonInfo buildGitCommitAuthor() { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BitBucketInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BitBucketInfo.java index 1c95c0d4bff..bb512031473 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BitBucketInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BitBucketInfo.java @@ -85,7 +85,7 @@ public PullRequestInfo buildPullRequestInfo() { } private String buildPipelineUrl(final String repo, final String number) { - return String.format( + return Strings.format( "https://bitbucket.org/%s/addon/pipelines/home#!/results/%s", repo, number); } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuddyInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuddyInfo.java index 69554f4a300..f943f548260 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuddyInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuddyInfo.java @@ -9,6 +9,7 @@ import datadog.trace.api.git.GitInfo; import datadog.trace.api.git.PersonInfo; import datadog.trace.civisibility.ci.env.CiEnvironment; +import datadog.trace.util.Strings; import javax.annotation.Nonnull; class BuddyInfo implements CIProviderInfo { @@ -80,7 +81,7 @@ private String getPipelineId(String pipelineNumber) { if (pipelineNumber == null) { return pipelineId; } - return String.format("%s/%s", pipelineId, pipelineNumber); + return Strings.format("%s/%s", pipelineId, pipelineNumber); } private PersonInfo buildGitCommiter() { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuildkiteInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuildkiteInfo.java index 935d4b9b147..77e37aefd92 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuildkiteInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/BuildkiteInfo.java @@ -11,6 +11,7 @@ import datadog.trace.api.git.GitInfo; import datadog.trace.api.git.PersonInfo; import datadog.trace.civisibility.ci.env.CiEnvironment; +import datadog.trace.util.Strings; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -73,7 +74,7 @@ public CIInfo buildCIInfo() { .ciPipelineNumber(environment.get(BUILDKITE_PIPELINE_NUMBER)) .ciPipelineUrl(ciPipelineUrl) .ciJobId(environment.get(BUILDKITE_JOB_ID)) - .ciJobUrl(String.format("%s#%s", ciPipelineUrl, environment.get(BUILDKITE_JOB_ID))) + .ciJobUrl(Strings.format("%s#%s", ciPipelineUrl, environment.get(BUILDKITE_JOB_ID))) .ciWorkspace(expandTilde(environment.get(BUILDKITE_WORKSPACE_PATH))) .ciNodeName(environment.get(BUILDKITE_AGENT_ID)) .ciNodeLabels(buildCiNodeLabels()) diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/CircleCIInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/CircleCIInfo.java index 24010c653f0..670bd538f53 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/CircleCIInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/CircleCIInfo.java @@ -9,6 +9,7 @@ import datadog.trace.api.git.CommitInfo; import datadog.trace.api.git.GitInfo; import datadog.trace.civisibility.ci.env.CiEnvironment; +import datadog.trace.util.Strings; import javax.annotation.Nonnull; class CircleCIInfo implements CIProviderInfo { @@ -71,7 +72,7 @@ private String buildPipelineUrl(final String pipelineId) { return null; } - return String.format("https://app.circleci.com/pipelines/workflows/%s", pipelineId); + return Strings.format("https://app.circleci.com/pipelines/workflows/%s", pipelineId); } @Override diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/GithubActionsInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/GithubActionsInfo.java index 856e280b933..fea85b0715c 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/GithubActionsInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/GithubActionsInfo.java @@ -204,25 +204,25 @@ private String buildGitRepositoryUrl(final String host, final String repo) { return null; } - return String.format("%s/%s.git", host, repo); + return Strings.format("%s/%s.git", host, repo); } private String buildPipelineUrl( final String host, final String repo, final String pipelineId, final String retry) { if (retry != null && !retry.isEmpty()) { - return String.format("%s/%s/actions/runs/%s/attempts/%s", host, repo, pipelineId, retry); + return Strings.format("%s/%s/actions/runs/%s/attempts/%s", host, repo, pipelineId, retry); } else { - return String.format("%s/%s/actions/runs/%s", host, repo, pipelineId); + return Strings.format("%s/%s/actions/runs/%s", host, repo, pipelineId); } } private String buildJobUrl(final String host, final String repo, final String commit) { - return String.format("%s/%s/commit/%s/checks", host, repo, commit); + return Strings.format("%s/%s/commit/%s/checks", host, repo, commit); } private String buildJobUrlWithNumericId( final String host, final String repo, final String pipelineId, final String jobId) { - return String.format("%s/%s/actions/runs/%s/job/%s", host, repo, pipelineId, jobId); + return Strings.format("%s/%s/actions/runs/%s/job/%s", host, repo, pipelineId, jobId); } /** diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/TravisInfo.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/TravisInfo.java index c5e56f5538d..d75fc9fb6a4 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/TravisInfo.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/ci/TravisInfo.java @@ -9,6 +9,7 @@ import datadog.trace.api.git.GitInfo; import datadog.trace.api.git.PersonInfo; import datadog.trace.civisibility.ci.env.CiEnvironment; +import datadog.trace.util.Strings; import javax.annotation.Nonnull; class TravisInfo implements CIProviderInfo { @@ -100,7 +101,7 @@ private String buildGitRepositoryUrl() { if (repoSlug == null || repoSlug.isEmpty()) { return null; } - return String.format("https://github.com/%s.git", repoSlug); + return Strings.format("https://github.com/%s.git", repoSlug); } private String buildCiPipelineName() { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ModuleSignalRouter.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ModuleSignalRouter.java index a0c1e6ee595..55f673f5186 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ModuleSignalRouter.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/domain/buildsystem/ModuleSignalRouter.java @@ -6,6 +6,7 @@ import datadog.trace.civisibility.ipc.Signal; import datadog.trace.civisibility.ipc.SignalResponse; import datadog.trace.civisibility.ipc.SignalType; +import datadog.trace.util.Strings; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; @@ -41,7 +42,7 @@ public SignalResponse onModuleSignalReceived(ModuleSignal result) { moduleHandlersById.get(moduleId); if (handlersByType == null) { String message = - String.format( + Strings.format( "Could not find signal handlers for module ID %s, test execution result will be ignored: %s", moduleId, result); LOGGER.warn(message); diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/GitConfig.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/GitConfig.java index a050163e489..56e04892e9e 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/GitConfig.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/GitConfig.java @@ -2,8 +2,10 @@ import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.BufferedReader; -import java.io.FileReader; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -30,7 +32,9 @@ private void load(final String path) { // url = https://some-host/user/repository.git // fetch = +refs/heads/*:refs/remotes/origin/* - try (final BufferedReader br = new BufferedReader(new FileReader(path))) { + try (final BufferedReader br = + new BufferedReader( + new InputStreamReader(new FileInputStream(path), StandardCharsets.UTF_8))) { String line; String section = null; while ((line = br.readLine()) != null) { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/LocalFSGitInfoExtractor.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/LocalFSGitInfoExtractor.java index 55832a06836..0fd822253b6 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/LocalFSGitInfoExtractor.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/LocalFSGitInfoExtractor.java @@ -12,6 +12,7 @@ import java.io.File; import java.io.FilenameFilter; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -189,7 +190,8 @@ private CommitInfo parseCommit( } // We get the reference in the object getting the bytes until the \n character: - final String objectSha = new String(Arrays.copyOfRange(gitObject.getContent(), 0, lf - 1)); + final String objectSha = + new String(Arrays.copyOfRange(gitObject.getContent(), 0, lf - 1), StandardCharsets.UTF_8); // Here, objectSha = "object $sha1". E.g: "object 44c242675ddf69b7b1f440b4a5d8d24e908d8bef" // Split by " " and get the sha in the second position of the array @@ -235,7 +237,8 @@ private GitObject buildGitObject(final byte[] compressedBytes) { // ((byte)32) // metadata[0] contains the type (e.g. commit) // metadata[1] contains the size (e.g. 261) - final String[] metadata = SPACE_PATTERN.split(new String(metadataBytes)); + final String[] metadata = + SPACE_PATTERN.split(new String(metadataBytes, StandardCharsets.UTF_8)); if (metadata.length != 2) { // Unexpected metadata format. return GitObject.NOOP; @@ -410,7 +413,7 @@ private String readFile(final Path filepath) throws IOException { return null; } - final String content = new String(Files.readAllBytes(filepath)); + final String content = new String(Files.readAllBytes(filepath), StandardCharsets.UTF_8); if (content.endsWith("\n")) { return content.substring(0, content.length() - 1); } diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/tree/ShellGitClient.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/tree/ShellGitClient.java index 8f63a088b28..a86078455c9 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/tree/ShellGitClient.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/git/tree/ShellGitClient.java @@ -194,7 +194,7 @@ public void unshallow(@Nullable String remoteCommitReference) "--update-shallow", "--filter=blob:none", "--recurse-submodules=no", - String.format("--shallow-since='%s'", latestCommitsSince), + Strings.format("--shallow-since='%s'", latestCommitsSince), remote, commitSha)); } else { @@ -205,7 +205,7 @@ public void unshallow(@Nullable String remoteCommitReference) "--update-shallow", "--filter=blob:none", "--recurse-submodules=no", - String.format("--shallow-since='%s'", latestCommitsSince), + Strings.format("--shallow-since='%s'", latestCommitsSince), remote)); } @@ -482,7 +482,7 @@ public List getLatestCommits() "--format=%H", "-n", String.valueOf(latestCommitsLimit), - String.format("--since='%s'", latestCommitsSince)))); + Strings.format("--since='%s'", latestCommitsSince)))); } /** @@ -510,7 +510,7 @@ public List getObjects( gitArgs[1] = "--objects"; gitArgs[2] = "--no-object-names"; gitArgs[3] = "--filter=blob:none"; - gitArgs[4] = String.format("--since='%s'", latestCommitsSince); + gitArgs[4] = Strings.format("--since='%s'", latestCommitsSince); int count = 5; for (String commitToSkip : commitsToSkip) { diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/utils/ShellCommandExecutor.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/utils/ShellCommandExecutor.java index 92103b75fd4..b665c396b5d 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/utils/ShellCommandExecutor.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/utils/ShellCommandExecutor.java @@ -13,6 +13,7 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.util.Collections; +import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -241,7 +242,7 @@ public static ExitCode getExitCode(Exception e) { } else { String m = e.getMessage(); - if (m != null && m.toLowerCase().contains("no such file or directory")) { + if (m != null && m.toLowerCase(Locale.ROOT).contains("no such file or directory")) { return ExitCode.EXECUTABLE_MISSING; } else { return ExitCode.CODE_UNKNOWN; diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploaderScriptInitializer.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploaderScriptInitializer.java index efaa86c84be..6382e3f74b4 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploaderScriptInitializer.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/CrashUploaderScriptInitializer.java @@ -151,7 +151,8 @@ private static void writeCrashUploaderScript( InputStream template, File scriptFile, String execClass, String crashFile) throws IOException { if (!scriptFile.exists()) { - try (BufferedReader br = new BufferedReader(new InputStreamReader(template)); + try (BufferedReader br = + new BufferedReader(new InputStreamReader(template, StandardCharsets.UTF_8)); BufferedWriter bw = new BufferedWriter( new OutputStreamWriter( diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/Initializer.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/Initializer.java index f8b68e1c1a9..4fd618dc9f6 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/Initializer.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/Initializer.java @@ -319,7 +319,7 @@ static String getScriptPathFromArg(String arg, String scriptNamePrefix) { if (arg == null || arg.isEmpty()) { return null; } - int idx = arg.toLowerCase().indexOf(scriptNamePrefix); + int idx = arg.toLowerCase(ROOT).indexOf(scriptNamePrefix); if (idx < 0) { // the script name is not present in the value, so we cannot extract the path return null; diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/ElfBuildIdExtractor.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/ElfBuildIdExtractor.java index 3f65a326dcb..9532cd4e772 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/ElfBuildIdExtractor.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/ElfBuildIdExtractor.java @@ -1,5 +1,6 @@ package datadog.crashtracking.buildid; +import datadog.trace.util.Strings; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; @@ -167,7 +168,7 @@ private String parseNoteSegment( // Convert to hex string StringBuilder hex = new StringBuilder(descsz * 2); for (byte b : buildIdBytes) { - hex.append(String.format("%02x", b & 0xff)); + hex.append(Strings.format("%02x", b & 0xff)); } return hex.toString(); } else { diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/PeBuildIdExtractor.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/PeBuildIdExtractor.java index 19a7afed4d5..d6981c4c657 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/PeBuildIdExtractor.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/buildid/PeBuildIdExtractor.java @@ -1,5 +1,6 @@ package datadog.crashtracking.buildid; +import datadog.trace.util.Strings; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; @@ -286,7 +287,7 @@ private long rvaToFileOffset( private String formatBuildId( long guidData1, int guidData2, int guidData3, byte[] guidData4, long age) { // Format: GUID (uppercase, without dashes) + Age (lowercase hex) - return String.format( + return Strings.format( "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x", guidData1, guidData2, diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java index f4cc8e6874f..1aeb30aa20c 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/HotspotCrashLogParser.java @@ -381,7 +381,7 @@ public CrashLog parse(String uuid, String crashLog) { } break; case MESSAGE: - if (line.toLowerCase().contains("core dump")) { + if (line.toLowerCase(Locale.ROOT).contains("core dump")) { // break out of the message block state = State.HEADER; } else if (oomMessage == null diff --git a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RuntimeArgs.java b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RuntimeArgs.java index 8a422f5166f..6e5ef316273 100644 --- a/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RuntimeArgs.java +++ b/dd-java-agent/agent-crashtracking/src/main/java/datadog/crashtracking/parsers/RuntimeArgs.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * Utility for normalizing and filtering JVM runtime arguments captured from crash artifacts. @@ -105,7 +106,7 @@ private static boolean hasSecretLikePropertyName(String arg) { } int separator = arg.indexOf('='); String propertyName = separator >= 0 ? arg.substring(2, separator) : arg.substring(2); - String normalizedPropertyName = propertyName.toLowerCase(); + String normalizedPropertyName = propertyName.toLowerCase(Locale.ROOT); for (String keyword : SECRET_PROPERTY_KEYWORDS) { if (normalizedPropertyName.contains(keyword)) { return true; diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueScript.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueScript.java index c446e0b12e5..033de75b68c 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueScript.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueScript.java @@ -39,6 +39,7 @@ import datadog.trace.bootstrap.debugger.el.ValueReferenceResolver; import datadog.trace.bootstrap.debugger.util.TimeoutChecker; import java.io.IOException; +import java.util.Locale; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -195,7 +196,7 @@ public Void visit(ComparisonExpression comparisonExpression) { @Override public Void visit(ComparisonOperator operator) { try { - jsonWriter.name(operator.name().toLowerCase()); + jsonWriter.name(operator.name().toLowerCase(Locale.ROOT)); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueType.java b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueType.java index 7066cbfb58f..5d7c3217648 100644 --- a/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueType.java +++ b/dd-java-agent/agent-debugger/debugger-el/src/main/java/com/datadog/debugger/el/ValueType.java @@ -1,5 +1,7 @@ package com.datadog.debugger.el; +import java.util.Locale; + public enum ValueType { OBJECT, BOOLEAN, @@ -21,7 +23,7 @@ public static String toString(ValueType type) { case SHORT: case CHAR: case FLOAT: - return type.name().toLowerCase(); + return type.name().toLowerCase(Locale.ROOT); default: return Object.class.getTypeName(); } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java index 290e4e047c5..4b501953bd7 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/DebuggerTransformer.java @@ -36,12 +36,14 @@ import datadog.trace.bootstrap.debugger.ProbeImplementation; import datadog.trace.util.RandomUtils; import datadog.trace.util.Strings; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.instrument.ClassFileTransformer; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -54,6 +56,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.function.BiConsumer; @@ -505,7 +508,10 @@ private boolean isClassLoaderRelated(ClassNode classNode) { } private synchronized void writeToInstrumentationLog(String classFilePath) { - try (FileWriter writer = new FileWriter("/tmp/debugger/instrumentation.log", true)) { + try (OutputStreamWriter writer = + new OutputStreamWriter( + new FileOutputStream("/tmp/debugger/instrumentation.log", true), + StandardCharsets.UTF_8)) { writer.write(classFilePath); writer.write("\n"); } catch (Exception ex) { @@ -622,7 +628,11 @@ private void verifyByteCode(String classFilePath, byte[] classFile) { analyzer.analyze(classNode.name, method); } catch (AnalyzerException e) { printWriter.printf( - "Error analyzing method '%s.%s%s':%n", classNode.name, method.name, method.desc); + Locale.ROOT, + "Error analyzing method '%s.%s%s':%n", + classNode.name, + method.name, + method.desc); e.printStackTrace(printWriter); } } @@ -711,7 +721,7 @@ private void reportLocationNotFound( if (methodName != null) { String signature = definition.getWhere().getSignature(); signature = signature == null ? "" : signature; - String msg = String.format(CANNOT_FIND_METHOD, className, methodName, signature); + String msg = Strings.format(CANNOT_FIND_METHOD, className, methodName, signature); reportErrorForAllProbes(singletonList(definition), msg); return; } @@ -721,7 +731,7 @@ private void reportLocationNotFound( private void reportInstrumentationFails( List definitions, String className, String errorMsg) { - String msg = String.format(INSTRUMENTATION_FAILS, className, errorMsg); + String msg = Strings.format(INSTRUMENTATION_FAILS, className, errorMsg); reportErrorForAllProbes(definitions, msg); } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ThirdPartyLibraries.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ThirdPartyLibraries.java index 94460055129..914f1c0e2fa 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ThirdPartyLibraries.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ThirdPartyLibraries.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -80,7 +81,7 @@ private static Set getExcludeAll() { } private static InternalConfig readConfig(InputStream inputStream) throws IOException { - try (InputStreamReader isr = new InputStreamReader(inputStream); + try (InputStreamReader isr = new InputStreamReader(inputStream, StandardCharsets.UTF_8); BufferedReader reader = new BufferedReader(isr)) { return ADAPTER.fromJson(reader.lines().collect(Collectors.joining(System.lineSeparator()))); } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/AbstractExceptionDebugger.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/AbstractExceptionDebugger.java index e92f65ef223..ae5102de0b3 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/AbstractExceptionDebugger.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/AbstractExceptionDebugger.java @@ -11,6 +11,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.util.AgentTaskScheduler; +import datadog.trace.util.Strings; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; @@ -128,7 +129,7 @@ private void applyExceptionConfiguration(String fingerprint) { protected void addStackFrameTags( AgentSpan span, Snapshot snapshot, int frameIndex, StackTraceElement stackFrame) { - String tagName = String.format(SNAPSHOT_ID_TAG_FMT, frameIndex); + String tagName = Strings.format(SNAPSHOT_ID_TAG_FMT, frameIndex); span.setTag(tagName, snapshot.getId()); LOGGER.debug("add tag to span[{}]: {}: {}", span.getSpanId(), tagName, snapshot.getId()); } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/FailedTestReplayExceptionDebugger.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/FailedTestReplayExceptionDebugger.java index b6e05940acf..cb8b97ca2b1 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/FailedTestReplayExceptionDebugger.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/exception/FailedTestReplayExceptionDebugger.java @@ -8,6 +8,7 @@ import datadog.trace.api.civisibility.execution.TestExecutionTracker; import datadog.trace.bootstrap.debugger.DebuggerContext; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import datadog.trace.util.Strings; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,8 +50,8 @@ protected void addStackFrameTags( AgentSpan span, Snapshot snapshot, int frameIndex, StackTraceElement stackFrame) { super.addStackFrameTags(span, snapshot, frameIndex, stackFrame); - String fileTag = String.format(TEST_DEBUG_ERROR_FILE_TAG_FMT, frameIndex); - String lineTag = String.format(TEST_DEBUG_ERROR_LINE_TAG_FMT, frameIndex); + String fileTag = Strings.format(TEST_DEBUG_ERROR_FILE_TAG_FMT, frameIndex); + String lineTag = Strings.format(TEST_DEBUG_ERROR_LINE_TAG_FMT, frameIndex); span.setTag(fileTag, stackFrame.getFileName()); span.setTag(lineTag, stackFrame.getLineNumber()); diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java index 49f384bc9fc..046f4111001 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/ASMHelper.java @@ -1,7 +1,6 @@ package com.datadog.debugger.instrumentation; import static com.datadog.debugger.instrumentation.Types.REFLECTIVE_FIELD_VALUE_RESOLVER_TYPE; -import static java.lang.String.format; import static org.objectweb.asm.Type.getMethodDescriptor; import static org.objectweb.asm.Type.getObjectType; @@ -15,6 +14,7 @@ import java.io.StringWriter; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -65,10 +65,10 @@ public static void dumpMethod(ClassNode classNode, String method, String suffix) File output; int count = 0; do { - output = new File(format("build/%s-%d-%s.txt", method, count++, suffix)); + output = new File(Strings.format("build/%s-%d-%s.txt", method, count++, suffix)); } while (output.exists()); output.getParentFile().mkdirs(); - try (PrintWriter writer = new PrintWriter(output)) { + try (PrintWriter writer = new PrintWriter(output, StandardCharsets.UTF_8.name())) { writer.println(content); String absolutePath = output.getAbsolutePath(); absolutePath = absolutePath.substring(0, absolutePath.lastIndexOf('.')); @@ -91,9 +91,9 @@ static String extractMethod(ClassNode classNode, String method) { classNode.accept(new TraceClassVisitor(null, new Textifier(), new PrintWriter(writer))); List strings = Arrays.asList(writer.toString().split("\n")); for (int i = 0; i < strings.size(); i++) { - if (strings.get(i).matches(format(".*(private|public).* %s\\(.*", method))) { + if (strings.get(i).matches(Strings.format(".*(private|public).* %s\\(.*", method))) { while (!strings.get(i).equals("")) - joiner.add(String.format("[%3d] %s", i, strings.get(i++))); + joiner.add(Strings.format("[%3d] %s", i, strings.get(i++))); } } return joiner.toString(); @@ -392,10 +392,10 @@ public static boolean isStoreCompatibleType( public static String toString(AbstractInsnNode node) { String opcode = node.getOpcode() >= 0 ? Printer.OPCODES[node.getOpcode()] : node.toString(); if (node instanceof LineNumberNode) { - return String.format("LineNumber: %s", ((LineNumberNode) node).line); + return Strings.format("LineNumber: %s", ((LineNumberNode) node).line); } else if (node instanceof MethodInsnNode) { MethodInsnNode method = (MethodInsnNode) node; - return String.format("%s: [%s] %s", opcode, method.name, method.desc); + return Strings.format("%s: [%s] %s", opcode, method.name, method.desc); } else { return opcode; } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumenter.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumenter.java index e22397cd8ed..0ce1de9a4c0 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumenter.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/CodeOriginInstrumenter.java @@ -4,12 +4,12 @@ import static com.datadog.debugger.instrumentation.ASMHelper.ldc; import static com.datadog.debugger.instrumentation.Types.DEBUGGER_CONTEXT_TYPE; import static java.lang.Integer.parseInt; -import static java.lang.String.format; import com.datadog.debugger.instrumentation.InstrumentationResult.Status; import com.datadog.debugger.probe.CodeOriginProbe; import com.datadog.debugger.probe.ProbeDefinition; import datadog.trace.bootstrap.debugger.DebuggerContext; +import datadog.trace.util.Strings; import java.util.List; import java.util.ListIterator; import org.objectweb.asm.Type; @@ -28,8 +28,8 @@ public class CodeOriginInstrumenter extends Instrumenter { static { String className = DebuggerContext.class.getName().replace('.', '/'); - CAPTURE = format("%s#%s", className, "captureCodeOrigin"); - MARKER = format("%s#%s", className, "marker"); + CAPTURE = Strings.format("%s#%s", className, "captureCodeOrigin"); + MARKER = Strings.format("%s#%s", className, "marker"); } public CodeOriginInstrumenter( @@ -49,7 +49,7 @@ public Status instrument() { private static String buildDescription(AbstractInsnNode node) { if (!(node instanceof MethodInsnNode)) return ""; MethodInsnNode method = (MethodInsnNode) node; - return format("%s#%s", method.owner, method.name); + return Strings.format("%s#%s", method.owner, method.name); } private InsnList codeOriginCall() { diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/InstrumentationResult.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/InstrumentationResult.java index 45b0161984a..7a8fc849a1a 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/InstrumentationResult.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/InstrumentationResult.java @@ -3,6 +3,7 @@ import com.datadog.debugger.agent.Generated; import com.datadog.debugger.probe.ProbeDefinition; import datadog.trace.bootstrap.debugger.ProbeId; +import datadog.trace.util.Strings; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -108,7 +109,7 @@ public String getMethodSignature() { @Generated @Override public String toString() { - return String.format( + return Strings.format( "InstrumentationResult{typeName='%s', methodName='%s', methodStart=%d, signature='%s'," + " sourceFileName='%s', status=%s. diagnostics=%s}", typeName, methodName, methodStart, signature, sourceFileName, status, diagnostics); diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MethodInfo.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MethodInfo.java index d58ad0251e0..6a08d28ff86 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MethodInfo.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MethodInfo.java @@ -61,7 +61,7 @@ public String getTypeName() { @Override public String toString() { - return String.format( + return Strings.format( "MethodInfo{classNode=%s, methodNode=%s}", classNode.name, methodNode.desc); } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MetricInstrumenter.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MetricInstrumenter.java index 9b41db1dd39..7eaf8e60b44 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MetricInstrumenter.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/MetricInstrumenter.java @@ -66,6 +66,7 @@ import com.datadog.debugger.util.ClassFileLines; import datadog.trace.bootstrap.debugger.MethodLocation; import datadog.trace.bootstrap.debugger.el.ValueReferences; +import datadog.trace.util.Strings; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; @@ -357,7 +358,7 @@ private InsnList internalCallMetric( .map(Type::getClassName) .collect(Collectors.joining(",")); reportError( - String.format( + Strings.format( "Incompatible type for expression: %s with expected types: [%s]", resultType.getClassName(), expectedTypes)); return EMPTY_INSN_LIST; @@ -422,7 +423,7 @@ private InsnList callMetric( } return internalCallMetric(metricProbe, targetLocation, returnContext); default: - reportError(String.format("Unknown metric kind: %s", metricProbe.getKind())); + reportError(Strings.format("Unknown metric kind: %s", metricProbe.getKind())); } return null; } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/Types.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/Types.java index c9f42e4d4b9..6cdfd1fa3c7 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/Types.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/instrumentation/Types.java @@ -23,6 +23,7 @@ import datadog.trace.bootstrap.debugger.MethodLocation; import datadog.trace.bootstrap.debugger.ProbeId; import datadog.trace.bootstrap.debugger.el.ReflectiveFieldValueResolver; +import datadog.trace.util.Strings; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -292,7 +293,7 @@ public static String descriptorFromSignature(String javaSignature) { int rightParen = javaSignature.indexOf(')'); if (leftParen == -1 || rightParen == -1) { throw new IllegalArgumentException( - String.format( + Strings.format( "Illegal java signature, missing matching parenthesis: '%s'. Must be of form ' (, ..., )'", javaSignature)); } @@ -305,7 +306,7 @@ public static String descriptorFromSignature(String javaSignature) { StringTokenizer st = new StringTokenizer(args, ","); if (!st.hasMoreTokens() && !args.isEmpty()) { throw new IllegalArgumentException( - String.format( + Strings.format( "Illegal java signature, invalid argument format: '%s'. Must be of form ' (, ..., )'", javaSignature)); } @@ -313,7 +314,7 @@ public static String descriptorFromSignature(String javaSignature) { String arg = st.nextToken().trim(); if (arg.length() == 0) { throw new IllegalArgumentException( - String.format( + Strings.format( "Illegal java signature, empty argument: '%s'. Must be of form ' (, ..., )'", javaSignature)); } @@ -328,7 +329,7 @@ public static String descriptorFromSignature(String javaSignature) { String returnType = javaSignature.substring(0, leftParen).trim(); if (returnType.length() == 0) { throw new IllegalArgumentException( - String.format( + Strings.format( "Illegal java signature: '%s'. Must be of form ' (, ..., )'", javaSignature)); } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java index c8d6e4a49e2..badca169647 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/CodeOriginProbe.java @@ -21,6 +21,7 @@ import datadog.trace.bootstrap.debugger.ProbeLocation; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.util.Strings; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -124,7 +125,7 @@ public int hashCode() { @Override public String toString() { - return String.format( + return Strings.format( "CodeOriginProbe{probeId=%s, entrySpanProbe=%s, signature=%s, where=%s, location=%s}", getProbeId(), entrySpanProbe, signature, where, location); } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/LogProbe.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/LogProbe.java index 548086744b2..1db8b567472 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/LogProbe.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/LogProbe.java @@ -4,7 +4,6 @@ import static com.datadog.debugger.probe.LogProbe.CoordinatedSamplingState.Status.DROP; import static com.datadog.debugger.probe.LogProbe.CoordinatedSamplingState.Status.EMIT; import static datadog.trace.api.debugger.DebuggerMetricCollector.SkippedReason.RATE_LIMIT; -import static java.lang.String.format; import com.datadog.debugger.agent.DebuggerAgent; import com.datadog.debugger.agent.Generated; @@ -47,6 +46,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentTracer.TracerAPI; import datadog.trace.core.DDSpan; import datadog.trace.core.DDSpanContext; +import datadog.trace.util.Strings; import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.IOException; import java.time.Duration; @@ -1173,7 +1173,7 @@ private void incrementBudget() { TracerAPI tracer = AgentTracer.get(); AgentSpan span = tracer != null ? tracer.activeSpan() : null; if (span != null) { - span.getLocalRootSpan().setTag(format("_dd.ld.probe_id.%s", id), budgetLevel.get()); + span.getLocalRootSpan().setTag(Strings.format("_dd.ld.probe_id.%s", id), budgetLevel.get()); } } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/Sampling.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/Sampling.java index 058da4fbb02..e584582a827 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/Sampling.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/Sampling.java @@ -1,5 +1,6 @@ package com.datadog.debugger.probe; +import datadog.trace.util.Strings; import java.util.Objects; /** Stores sampling configuration */ @@ -70,7 +71,7 @@ public int hashCode() { @Override public String toString() { - return String.format( + return Strings.format( "Sampling{coolDownInSeconds=%d, eventsPerSecond=%s}", coolDownInSeconds, eventsPerSecond); } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/SpanDecorationProbe.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/SpanDecorationProbe.java index a9213d75409..44b76e3d363 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/SpanDecorationProbe.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/SpanDecorationProbe.java @@ -24,6 +24,7 @@ import datadog.trace.bootstrap.debugger.util.TimeoutChecker; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; +import datadog.trace.util.Strings; import datadog.trace.util.TagsHelper; import java.time.Duration; import java.util.ArrayList; @@ -268,13 +269,13 @@ public void evaluate( status.getErrors().addAll(logStatus.getErrors()); if (logStatus.getErrors().size() > 0) { spanStatus.addTag( - String.format(EVALERROR_DD_TAGS_FORMAT, tagName), + Strings.format(EVALERROR_DD_TAGS_FORMAT, tagName), logStatus.getErrors().get(0).getMessage()); } } else { spanStatus.addTag(tagName, tagValue); } - spanStatus.addTag(String.format(PROBEID_DD_TAGS_FORMAT, tagName), getProbeId().getId()); + spanStatus.addTag(Strings.format(PROBEID_DD_TAGS_FORMAT, tagName), getProbeId().getId()); } } } diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/TriggerProbe.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/TriggerProbe.java index e20f7c39d01..7954445c87a 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/TriggerProbe.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/probe/TriggerProbe.java @@ -1,7 +1,5 @@ package com.datadog.debugger.probe; -import static java.lang.String.format; - import com.datadog.debugger.agent.DebuggerAgent; import com.datadog.debugger.agent.Generated; import com.datadog.debugger.el.ProbeCondition; @@ -20,6 +18,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.Tags; +import datadog.trace.util.Strings; import java.time.Duration; import java.util.Arrays; import java.util.List; @@ -153,7 +152,7 @@ private void decorateTags() { AgentSpan agentSpan = tracerAPI.activeSpan().getLocalRootSpan(); agentSpan.setTag(Tags.PROPAGATED_DEBUG, sessionId + ":1"); - agentSpan.setTag(format("_dd.ld.probe_id.%s", getProbeId().getId()), true); + agentSpan.setTag(Strings.format("_dd.ld.probe_id.%s", getProbeId().getId()), true); } @Override @@ -190,7 +189,7 @@ public int hashCode() { @Override public String toString() { - return String.format( + return Strings.format( "TriggerProbe{id='%s', sessionId='%s', evaluateAt=%s, language='%s', location=%s, probeCondition=%s, probeId=%s," + " sampling=%s, tagMap=%s, tags=%s, version=%d, where=%s}", id, diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SymbolSink.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SymbolSink.java index ecb064ac251..ce3b59b0b5c 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SymbolSink.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/sink/SymbolSink.java @@ -11,6 +11,7 @@ import com.squareup.moshi.JsonAdapter; import datadog.trace.api.Config; import datadog.trace.util.RandomUtils; +import datadog.trace.util.Strings; import datadog.trace.util.TagsHelper; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -180,7 +181,7 @@ private void doUpload( private BatchUploader.MultiPartContent buildEvent(long currentBatch, int attachmentSize) { byte[] eventContent = - String.format( + Strings.format( EVENT_FORMAT, serviceName, version, diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/BasicSymDBReport.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/BasicSymDBReport.java index 3bb871a9e6c..96a69f0011b 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/BasicSymDBReport.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/BasicSymDBReport.java @@ -1,5 +1,6 @@ package com.datadog.debugger.symbol; +import datadog.trace.util.Strings; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -42,7 +43,7 @@ public void addScannedJar(String jarPath) { public void report() { int totalClasses = classCountByJar.values().stream().mapToInt(Integer::intValue).sum(); String content = - String.format( + Strings.format( "SymDB Report: Scanned jar count=%d, Total class count=%d, class count by jar: %s, Scanned jars: %s, Location errors: %s Missing jars: %s IOExceptions: %s", scannedJars.size(), totalClasses, diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java index 3fbb52cb0de..1f3a0ff7c84 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/propagation/StringModuleImpl.java @@ -18,6 +18,7 @@ import datadog.trace.api.iast.IastContext; import datadog.trace.api.iast.Taintable; import datadog.trace.api.iast.propagation.StringModule; +import datadog.trace.util.Strings; import de.thetaphi.forbiddenapis.SuppressForbidden; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Arrays; @@ -42,7 +43,7 @@ public class StringModuleImpl implements StringModule { /** Escaped format patterns * */ private static final Map ESCAPED_PATTERNS = - Stream.of("%%", "%n").collect(Collectors.toMap(Function.identity(), String::format)); + Stream.of("%%", "%n").collect(Collectors.toMap(Function.identity(), Strings::format)); private static final Ranged END = Ranged.build(Integer.MAX_VALUE, 0); diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/LdapRegexTokenizer.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/LdapRegexTokenizer.java index 5e3f84adafa..e1012acdb81 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/LdapRegexTokenizer.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/LdapRegexTokenizer.java @@ -3,6 +3,7 @@ import com.datadog.iast.model.Evidence; import com.datadog.iast.util.Ranged; import com.google.re2j.Pattern; +import datadog.trace.util.Strings; /** * @see Lightweight Directory Access Protocol @@ -14,7 +15,7 @@ public class LdapRegexTokenizer extends AbstractRegexTokenizer { private static final Pattern LDAP_PATTERN = Pattern.compile( - String.format("\\(.*?(?:~=|=|<=|>=)(?P<%s>[^)]+)\\)", LITERAL_GROUP), Pattern.MULTILINE); + Strings.format("\\(.*?(?:~=|=|<=|>=)(?P<%s>[^)]+)\\)", LITERAL_GROUP), Pattern.MULTILINE); public LdapRegexTokenizer(final Evidence evidence) { super(LDAP_PATTERN, evidence.getValue()); diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/SqlRegexpTokenizer.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/SqlRegexpTokenizer.java index 51587036686..6f38082cc94 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/SqlRegexpTokenizer.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/SqlRegexpTokenizer.java @@ -6,6 +6,7 @@ import com.datadog.iast.util.Ranged; import com.google.re2j.Matcher; import com.google.re2j.Pattern; +import datadog.trace.util.Strings; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -31,7 +32,7 @@ public class SqlRegexpTokenizer implements SensitiveHandler.Tokenizer { private static final String HEX_NUMBER = "x'[0-9a-f]+'|0x[0-9a-f]+"; private static final String BIN_NUMBER = "b'[0-9a-f]+'|0b[0-9a-f]+"; private static final String NUMERIC_LITERAL = - String.format( + Strings.format( "[-+]?(?:%s)", String.join( "|", HEX_NUMBER, BIN_NUMBER, DECIMAL_NUMBER + EXPONENT, INTEGER_NUMBER + EXPONENT)); diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/UrlRegexpTokenizer.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/UrlRegexpTokenizer.java index 06e1001a637..e66dd6b2911 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/UrlRegexpTokenizer.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sensitive/UrlRegexpTokenizer.java @@ -3,6 +3,7 @@ import com.datadog.iast.model.Evidence; import com.datadog.iast.util.Ranged; import com.google.re2j.Pattern; +import datadog.trace.util.Strings; /** * @see [^@]+)@", AUTHORITY_GROUP); + Strings.format("^(?:[^:]+:)?//(?P<%s>[^@]+)@", AUTHORITY_GROUP); private static final String QUERY_FRAGMENT = - String.format("[?#&]([^=&;]+)=(?P<%s>[^?#&]+)", QUERY_FRAGMENT_GROUP); + Strings.format("[?#&]([^=&;]+)=(?P<%s>[^?#&]+)", QUERY_FRAGMENT_GROUP); private static final Pattern PATTERN = Pattern.compile(String.join("|", AUTHORITY, QUERY_FRAGMENT)); diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/InsecureAuthProtocolModuleImpl.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/InsecureAuthProtocolModuleImpl.java index cd59059d230..9fc9afb7f1f 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/InsecureAuthProtocolModuleImpl.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/InsecureAuthProtocolModuleImpl.java @@ -7,6 +7,7 @@ import datadog.trace.api.gateway.IGSpanInfo; import datadog.trace.api.iast.IastContext; import datadog.trace.api.iast.sink.InsecureAuthProtocolModule; +import datadog.trace.util.Strings; import java.util.Map; import javax.annotation.Nullable; @@ -39,7 +40,7 @@ public void onRequestEnd(IastContext ctx, IGSpanInfo igSpanInfo) { if (authScheme == null) { return; } - final Evidence result = new Evidence(String.format("Authorization : %s", authScheme)); + final Evidence result = new Evidence(Strings.format("Authorization : %s", authScheme)); report(VulnerabilityType.INSECURE_AUTH_PROTOCOL, result); } diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/SinkModuleBase.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/SinkModuleBase.java index 38c66cb4c53..427f88dc3be 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/SinkModuleBase.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/sink/SinkModuleBase.java @@ -29,6 +29,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.instrumentation.iastinstrumenter.IastExclusionTrie; import datadog.trace.instrumentation.iastinstrumenter.SourceMapperImpl; +import datadog.trace.util.Strings; import datadog.trace.util.stacktrace.StackWalker; import java.util.Iterator; import java.util.function.Predicate; @@ -134,7 +135,7 @@ protected final Evidence checkInjection( value = origin; } else { valueRanges = Ranges.forObject((Source) taintable.$$DD$getSource(), type.mark()); - value = String.format("Tainted reference detected in " + value.getClass()); + value = Strings.format("Tainted reference detected in " + value.getClass()); } } else { final TaintedObject tainted = to.get(value); diff --git a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/taint/TaintedMap.java b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/taint/TaintedMap.java index 63f77c7ca28..feb1c63fb76 100644 --- a/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/taint/TaintedMap.java +++ b/dd-java-agent/agent-iast/src/main/java/com/datadog/iast/taint/TaintedMap.java @@ -7,6 +7,7 @@ import datadog.trace.api.iast.telemetry.IastMetricCollector; import datadog.trace.api.iast.telemetry.Verbosity; import datadog.trace.util.AgentTaskScheduler; +import datadog.trace.util.Strings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Arrays; import java.util.Collections; @@ -420,7 +421,7 @@ protected void computeStatistics() { } private static String percentage(final long actual, final long total) { - return String.format("%2.2f%%", total == 0 ? 0 : (actual * 100D / total)); + return Strings.format("%2.2f%%", total == 0 ? 0 : (actual * 100D / total)); } /** Computes different percentiles, values array MUST be sorted beforehand */ @@ -442,11 +443,11 @@ private static String percentile(final int[] values, final int percentile) { value = values[Math.round(values.length * percentile / 100F)]; break; } - return String.format("%s:%s", prefix, value); + return Strings.format("%s:%s", prefix, value); } private static String average(final int[] values) { - return String.format("avg:%2.2f", Arrays.stream(values).sum() / (double) values.length); + return Strings.format("avg:%2.2f", Arrays.stream(values).sum() / (double) values.length); } } diff --git a/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/usm/UsmExtractorImpl.java b/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/usm/UsmExtractorImpl.java index 51a3108b97f..31f8d8e4482 100644 --- a/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/usm/UsmExtractorImpl.java +++ b/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/usm/UsmExtractorImpl.java @@ -7,6 +7,7 @@ import datadog.trace.agent.tooling.usm.UsmMessageImpl.BaseUsmMessage; import datadog.trace.bootstrap.instrumentation.usm.UsmExtractor; import datadog.trace.bootstrap.instrumentation.usm.UsmMessage; +import datadog.trace.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,13 +25,13 @@ public void send(UsmMessage message) { BaseUsmMessage bm = (BaseUsmMessage) message; log.debug( - " sending ioctl: {}", String.format("%08x", UsmMessageImpl.USM_IOCTL_ID.intValue())); + " sending ioctl: {}", Strings.format("%08x", UsmMessageImpl.USM_IOCTL_ID.intValue())); NativeLong res = CLibrary.Instance.ioctl( new NativeLong(0), UsmMessageImpl.USM_IOCTL_ID, Pointer.nativeValue(bm.getBufferPtr())); - log.debug("ioctl result: {}", String.format("%08x", res.intValue())); + log.debug("ioctl result: {}", Strings.format("%08x", res.intValue())); } else { log.debug("INVALID MESSAGE: {}", message.getClass()); } diff --git a/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java b/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java index a46b1cb81a1..31182d0a3c9 100644 --- a/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java +++ b/dd-java-agent/agent-jmxfetch/src/main/java/datadog/trace/agent/jmxfetch/JMXFetch.java @@ -16,9 +16,11 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Scanner; import java.util.SortedSet; @@ -194,7 +196,7 @@ private static List getInternalMetricFiles() { return Collections.emptyList(); } log.debug("reading found metricconfigs"); - Scanner scanner = new Scanner(metricConfigsStream); + Scanner scanner = new Scanner(metricConfigsStream, StandardCharsets.UTF_8.name()); scanner.useDelimiter("\n"); final List result = new ArrayList<>(); final SortedSet integrationName = new TreeSet<>(); @@ -240,6 +242,6 @@ private static String getLogLocation() { private static String getLogLevel() { return SystemProperties.getOrDefault("org.slf4j.simpleLogger.defaultLogLevel", "info") - .toUpperCase(); + .toUpperCase(Locale.ROOT); } } diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/PrintStreamWrapper.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/PrintStreamWrapper.java index c71390a8e23..77df4555642 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/PrintStreamWrapper.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/PrintStreamWrapper.java @@ -2,6 +2,7 @@ import datadog.environment.OperatingSystem; import datadog.trace.api.internal.VisibleForTesting; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.OutputStream; @@ -14,6 +15,8 @@ public class PrintStreamWrapper extends PrintStream { private volatile int currentSize = 0; private PrintStream capturingStream = null; + // Preserve the JDK's encoding choice for the wrapped logging stream. + @SuppressForbidden public PrintStreamWrapper(PrintStream ps) { super(ps); } @@ -45,6 +48,8 @@ public void println(Object x) { println(s); } + // Log capture retains the platform encoding for compatibility. + @SuppressForbidden public void startCapturing(Path filepath) { stopCapturing(); try { diff --git a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java index f3cc1a57a27..c9c50ab1723 100644 --- a/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java +++ b/dd-java-agent/agent-logging/src/main/java/datadog/trace/logging/simplelogger/SLCompatSettings.java @@ -111,7 +111,9 @@ public static class LegacyDTFormatter extends DTFormatter { private final DateFormat dateFormat; public LegacyDTFormatter(String dateTimeFormat) { - this.dateFormat = new SimpleDateFormat(dateTimeFormat); + // User-configured log timestamps follow the JVM's formatting locale. + this.dateFormat = + new SimpleDateFormat(dateTimeFormat, Locale.getDefault(Locale.Category.FORMAT)); } @Override diff --git a/dd-java-agent/agent-profiling/profiling-controller-ddprof/src/main/java/com/datadog/profiling/controller/ddprof/DatadogProfilerSettings.java b/dd-java-agent/agent-profiling/profiling-controller-ddprof/src/main/java/com/datadog/profiling/controller/ddprof/DatadogProfilerSettings.java index b2746b82e5e..15c7c6f7995 100644 --- a/dd-java-agent/agent-profiling/profiling-controller-ddprof/src/main/java/com/datadog/profiling/controller/ddprof/DatadogProfilerSettings.java +++ b/dd-java-agent/agent-profiling/profiling-controller-ddprof/src/main/java/com/datadog/profiling/controller/ddprof/DatadogProfilerSettings.java @@ -4,6 +4,7 @@ import com.datadog.profiling.ddprof.DatadogProfiler; import datadog.common.version.VersionInfo; import datadog.trace.bootstrap.config.provider.ConfigProvider; +import java.util.Locale; public class DatadogProfilerSettings extends ProfilerSettingsSupport { @@ -42,7 +43,7 @@ public void publish() { datadogProfiler.recordSetting( PROFILER_ACTIVATION, profilerActivationSetting.enablement.getAlias()); datadogProfiler.recordSetting( - SSI_MECHANISM, profilerActivationSetting.ssiMechanism.name().toLowerCase()); + SSI_MECHANISM, profilerActivationSetting.ssiMechanism.name().toLowerCase(Locale.ROOT)); } @Override diff --git a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/JfrProfilerSettings.java b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/JfrProfilerSettings.java index f74d626909a..85ef4bbea67 100644 --- a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/JfrProfilerSettings.java +++ b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/JfrProfilerSettings.java @@ -7,6 +7,7 @@ import datadog.environment.JavaVirtualMachine; import datadog.trace.api.Platform; import datadog.trace.bootstrap.config.provider.ConfigProvider; +import java.util.Locale; /** Capture the profiler config first and allow emitting the setting events per each recording. */ final class JfrProfilerSettings extends ProfilerSettingsSupport { @@ -85,7 +86,7 @@ public void publish() { new ProfilerSettingEvent(PROFILER_ACTIVATION, profilerActivationSetting.enablement.getAlias()) .commit(); new ProfilerSettingEvent( - SSI_MECHANISM, profilerActivationSetting.ssiMechanism.name().toLowerCase()) + SSI_MECHANISM, profilerActivationSetting.ssiMechanism.name().toLowerCase(Locale.ROOT)) .commit(); } } diff --git a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/events/SmapEntryCache.java b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/events/SmapEntryCache.java index b890904a461..1e7a338fe00 100644 --- a/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/events/SmapEntryCache.java +++ b/dd-java-agent/agent-profiling/profiling-controller-openjdk/src/main/java/com/datadog/profiling/controller/openjdk/events/SmapEntryCache.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.lang.management.ManagementFactory; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -302,7 +303,9 @@ private static Map getAnnotatedRegions() { private void collectEvents(List events) { try (BufferedReader br = - new BufferedReader(new InputStreamReader(Files.newInputStream(smapsPath)), 64 * 1024)) { + new BufferedReader( + new InputStreamReader(Files.newInputStream(smapsPath), StandardCharsets.UTF_8), + 64 * 1024)) { readEvents(br, events); Map regions = getAnnotatedRegions(); for (SmapEntryEvent e : events) { diff --git a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java index a60e6b8f1dc..623d0c3a32b 100644 --- a/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java +++ b/dd-java-agent/agent-profiling/profiling-controller/src/main/java/com/datadog/profiling/controller/ProfilerSettingsSupport.java @@ -13,6 +13,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -241,7 +242,9 @@ private String getSELinuxStatus() { // we are expecting just a single line output from `getenforce`, so we can avoid draining // stdout/stderr asynchronously try (BufferedReader reader = - new BufferedReader(new InputStreamReader(process.getInputStream()))) { + // The native getenforce command uses the platform encoding. + new BufferedReader( + new InputStreamReader(process.getInputStream(), Charset.defaultCharset()))) { String line = reader.readLine(); if (line != null) { diff --git a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java index 6360f809ac2..9081f23f479 100644 --- a/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java +++ b/dd-java-agent/agent-profiling/profiling-ddprof/src/main/java/com/datadog/profiling/ddprof/DatadogProfiler.java @@ -50,6 +50,7 @@ import datadog.trace.api.profiling.RecordingData; import datadog.trace.bootstrap.config.provider.ConfigProvider; import datadog.trace.bootstrap.instrumentation.api.TaskWrapper; +import datadog.trace.util.Strings; import datadog.trace.util.TempLocationManager; import java.io.IOException; import java.nio.file.Files; @@ -490,7 +491,7 @@ String cmdStartProfiling(Path file) throws IllegalStateException { if (configuredProfilingModes.contains(MEMLEAK)) { cmd.append(isLiveHeapSizeTrackingEnabled(configProvider) ? 'L' : 'l'); cmd.append(':') - .append(String.format("%.2f", getLiveHeapSamplePercent(configProvider) / 100.0d)); + .append(Strings.format("%.2f", getLiveHeapSamplePercent(configProvider) / 100.0d)); } } if (configuredProfilingModes.contains(NATIVEMEM)) { diff --git a/dd-java-agent/agent-profiling/profiling-uploader/src/main/java/com/datadog/profiling/uploader/util/JfrCliHelper.java b/dd-java-agent/agent-profiling/profiling-uploader/src/main/java/com/datadog/profiling/uploader/util/JfrCliHelper.java index 1348c5b2dea..acddc587169 100644 --- a/dd-java-agent/agent-profiling/profiling-uploader/src/main/java/com/datadog/profiling/uploader/util/JfrCliHelper.java +++ b/dd-java-agent/agent-profiling/profiling-uploader/src/main/java/com/datadog/profiling/uploader/util/JfrCliHelper.java @@ -7,11 +7,13 @@ import datadog.logging.IOLogger; import datadog.trace.api.profiling.RecordingData; import datadog.trace.util.AgentThreadFactory; +import datadog.trace.util.Strings; import datadog.trace.util.TempLocationManager; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -88,7 +90,8 @@ public static void invokeOn(final RecordingData data, final IOLogger ioLogger) { asyncRedirect.get(); - stdout = lineSeparatorRegex.split(out.toString()); + // The subprocess writes its output in the platform encoding. + stdout = lineSeparatorRegex.split(out.toString(Charset.defaultCharset().name())); } finally { process.destroy(); } @@ -132,7 +135,7 @@ public static void invokeOn(final RecordingData data, final IOLogger ioLogger) { .forEach( event -> { ioLogger.error( - String.format( + Strings.format( "Event: %s, size = %d, count = %d", event.getType(), event.getSize(), event.getCount())); }); diff --git a/dd-java-agent/agent-tooling/src/jmh/java/datadog/trace/agent/tooling/bytebuddy/csi/CallSiteBenchmark.java b/dd-java-agent/agent-tooling/src/jmh/java/datadog/trace/agent/tooling/bytebuddy/csi/CallSiteBenchmark.java index 38151b6c307..b9a2efc4efb 100644 --- a/dd-java-agent/agent-tooling/src/jmh/java/datadog/trace/agent/tooling/bytebuddy/csi/CallSiteBenchmark.java +++ b/dd-java-agent/agent-tooling/src/jmh/java/datadog/trace/agent/tooling/bytebuddy/csi/CallSiteBenchmark.java @@ -3,6 +3,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import datadog.trace.agent.tooling.AgentInstaller; +import datadog.trace.util.Strings; import java.lang.instrument.Instrumentation; import net.bytebuddy.agent.ByteBuddyAgent; import org.openjdk.jmh.annotations.Benchmark; @@ -82,7 +83,7 @@ public void validate(final String response) { String expected = instrumentation == null ? "Hello!" : "Hello! [Transformed]"; if (!expected.equals(response)) { throw new RuntimeException( - String.format("Wrong response, expected '%s' but received '%s'", expected, response)); + Strings.format("Wrong response, expected '%s' but received '%s'", expected, response)); } } } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/InstrumenterMetrics.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/InstrumenterMetrics.java index bc54ebf5777..1178ced5e6d 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/InstrumenterMetrics.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/InstrumenterMetrics.java @@ -1,6 +1,7 @@ package datadog.trace.agent.tooling; import datadog.trace.api.InstrumenterConfig; +import datadog.trace.util.Strings; import java.util.concurrent.atomic.AtomicLong; public final class InstrumenterMetrics { @@ -205,9 +206,9 @@ public static String summary() { private static void summarize(StringBuilder buf, String prefix, AtomicLong stat) { long value = stat.get(); buf.append(prefix) - .append(String.format("%-12d", value >>> COUNT_SHIFT)) + .append(Strings.format("%-12d", value >>> COUNT_SHIFT)) .append(' ') - .append(String.format("%.1f", (value & NANOS_MASK) / 1_000_000.0)) + .append(Strings.format("%.1f", (value & NANOS_MASK) / 1_000_000.0)) .append(" ms\n"); } } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/csi/Advices.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/csi/Advices.java index 58cbe2eb856..7e80dc7b088 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/csi/Advices.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/csi/Advices.java @@ -8,6 +8,7 @@ import datadog.trace.agent.tooling.csi.CallSites; import datadog.trace.agent.tooling.csi.InvokeAdvice; import datadog.trace.agent.tooling.csi.InvokeDynamicAdvice; +import datadog.trace.util.Strings; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; @@ -196,7 +197,7 @@ public void addAdvice( methodAdvices.put(descriptor, TypedAdvice.withType(advice, type)); if (oldAdvice != null) { throw new UnsupportedOperationException( - String.format( + Strings.format( "Advice %s and %s match the same pointcut, this is not yet supported", oldAdvice, advice)); } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedContextRequestRewriter.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedContextRequestRewriter.java index edbb757b9e0..8d929022fde 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedContextRequestRewriter.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedContextRequestRewriter.java @@ -6,6 +6,7 @@ import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.ContextStores; import datadog.trace.bootstrap.InstrumentationContext; +import datadog.trace.util.Strings; import java.util.Map; import net.bytebuddy.asm.AsmVisitorWrapper; import net.bytebuddy.description.field.FieldDescription; @@ -138,7 +139,7 @@ public void visitMethodInsn( } if (!contextClassName.equals(contextStore.get(keyClassName))) { throw new IllegalStateException( - String.format( + Strings.format( "Incorrect Context Api Usage detected. Incorrect context class %s, expected %s for instrumentation %s", contextClassName, contextStore.get(keyClassName), instrumenterClassName)); } diff --git a/dd-java-agent/instrumentation-annotation-processor/src/main/java/datadog/apt/LogUtils.java b/dd-java-agent/instrumentation-annotation-processor/src/main/java/datadog/apt/LogUtils.java index 34c0925ff4c..94d00ec449c 100644 --- a/dd-java-agent/instrumentation-annotation-processor/src/main/java/datadog/apt/LogUtils.java +++ b/dd-java-agent/instrumentation-annotation-processor/src/main/java/datadog/apt/LogUtils.java @@ -1,5 +1,6 @@ package datadog.apt; +import java.util.Locale; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; import javax.tools.Diagnostic.Kind; @@ -11,7 +12,7 @@ private LogUtils() {} private static final boolean NOTE = false; public static void log(ProcessingEnvironment processingEnv, String formatStr, Object... args) { - String msg = String.format(formatStr, args); + String msg = String.format(Locale.ROOT, formatStr, args); if (NOTE) { processingEnv.getMessager().printMessage(Kind.NOTE, msg); @@ -34,7 +35,7 @@ public static void message( Kind kind, String formatStr, Object... args) { - String msg = String.format(formatStr, args); + String msg = String.format(Locale.ROOT, formatStr, args); if (kind != Kind.NOTE || NOTE) { processingEnv.getMessager().printMessage(kind, msg, element); diff --git a/dd-java-agent/instrumentation-testing/src/main/java/datadog/trace/agent/test/scopediag/ScopeDiagnosticsReport.java b/dd-java-agent/instrumentation-testing/src/main/java/datadog/trace/agent/test/scopediag/ScopeDiagnosticsReport.java index c8e1da8fe38..301564ca8cf 100644 --- a/dd-java-agent/instrumentation-testing/src/main/java/datadog/trace/agent/test/scopediag/ScopeDiagnosticsReport.java +++ b/dd-java-agent/instrumentation-testing/src/main/java/datadog/trace/agent/test/scopediag/ScopeDiagnosticsReport.java @@ -1,6 +1,7 @@ package datadog.trace.agent.test.scopediag; import datadog.trace.api.DDTraceId; +import datadog.trace.util.Strings; import java.util.ArrayList; import java.util.EnumSet; import java.util.LinkedHashMap; @@ -437,10 +438,10 @@ private void appendEvent(StringBuilder sb, String label, ScopeEvent event) { } private String relMillis(long nanos) { - return String.format("%.3f", (nanos - t0) / 1_000_000.0); + return Strings.format("%.3f", (nanos - t0) / 1_000_000.0); } private static String millis(long nanos) { - return String.format("%.3f", nanos / 1_000_000.0); + return Strings.format("%.3f", nanos / 1_000_000.0); } } diff --git a/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/ResourcesFeatureInstrumentation.java b/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/ResourcesFeatureInstrumentation.java index bdc78bed041..c7676a05f03 100644 --- a/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/ResourcesFeatureInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/ResourcesFeatureInstrumentation.java @@ -8,6 +8,7 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import net.bytebuddy.asm.Advice; @@ -62,7 +63,8 @@ public static void onExit() { String metricConfigs = metricConfigsPath + "metricconfigs.txt"; tracerResources.add(metricConfigs); try (InputStream is = ClassLoader.getSystemResourceAsStream(metricConfigs); - BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + BufferedReader reader = + new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { String metricConfig; while ((metricConfig = reader.readLine()) != null) { if (!metricConfig.trim().isEmpty()) { diff --git a/dd-java-agent/instrumentation/gradle/gradle-3.0/src/main/groovy/datadog/trace/instrumentation/gradle/legacy/GradleUtils.groovy b/dd-java-agent/instrumentation/gradle/gradle-3.0/src/main/groovy/datadog/trace/instrumentation/gradle/legacy/GradleUtils.groovy index 23b271df617..74f7c294b91 100644 --- a/dd-java-agent/instrumentation/gradle/gradle-3.0/src/main/groovy/datadog/trace/instrumentation/gradle/legacy/GradleUtils.groovy +++ b/dd-java-agent/instrumentation/gradle/gradle-3.0/src/main/groovy/datadog/trace/instrumentation/gradle/legacy/GradleUtils.groovy @@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory import java.nio.file.Path import java.nio.file.Paths +import java.util.Locale abstract class GradleUtils { @@ -74,7 +75,7 @@ abstract class GradleUtils { def srcDirs = sourceSet.allSource.srcDirs def destinationDirs = sourceSet.output.files - SourceSet.Type type = sourceSet.name.toLowerCase().contains("test") ? SourceSet.Type.TEST : SourceSet.Type.CODE + SourceSet.Type type = sourceSet.name.toLowerCase(Locale.ROOT).contains("test") ? SourceSet.Type.TEST : SourceSet.Type.CODE sourceSets.add(new SourceSet(type, srcDirs, destinationDirs)) } return new BuildModuleLayout(sourceSets) diff --git a/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityGradleListener.java b/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityGradleListener.java index 5015f3778be..ffc06a58439 100644 --- a/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityGradleListener.java +++ b/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityGradleListener.java @@ -6,8 +6,10 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -49,7 +51,8 @@ public class CiVisibilityGradleListener extends BuildAdapter try (BufferedReader reader = new BufferedReader( new InputStreamReader( - ClassLoader.getSystemResourceAsStream("dd-java-agent.version")))) { + ClassLoader.getSystemResourceAsStream("dd-java-agent.version"), + StandardCharsets.UTF_8))) { TRACER_VERSION = reader.lines().collect(Collectors.joining()); } catch (IOException e) { throw new RuntimeException("Could not read tracer version from dd-java-agent.version", e); @@ -222,7 +225,7 @@ private JavaAgent getJacocoAgent(Test task) { } Named namedProvider = (Named) jvmArgumentProvider; String providerName = namedProvider.getName(); - if (!providerName.toLowerCase().contains("jacoco")) { + if (!providerName.toLowerCase(Locale.ROOT).contains("jacoco")) { continue; } Iterable arguments = jvmArgumentProvider.asArguments(); diff --git a/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityPlugin.java b/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityPlugin.java index 4d7ad9c2c26..63794b62aed 100644 --- a/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityPlugin.java +++ b/dd-java-agent/instrumentation/gradle/gradle-8.3/src/main/groovy/datadog/trace/instrumentation/gradle/CiVisibilityPlugin.java @@ -2,6 +2,7 @@ import datadog.trace.api.Config; import datadog.trace.api.civisibility.domain.BuildModuleLayout; +import datadog.trace.util.Strings; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; @@ -9,6 +10,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -65,7 +67,7 @@ private void calculateCompiledClassesFolders(CiVisibilityPluginExtension extensi SourceSet sourceSet = gradleSourceSets.findByName(sourceSetName); if (sourceSet != null) { datadog.trace.api.civisibility.domain.SourceSet.Type sourceSetType = - sourceSet.getName().toLowerCase().contains("test") + sourceSet.getName().toLowerCase(Locale.ROOT).contains("test") ? datadog.trace.api.civisibility.domain.SourceSet.Type.TEST : datadog.trace.api.civisibility.domain.SourceSet.Type.CODE; @@ -100,13 +102,13 @@ public void addCompilerPluginConfigurations(CiVisibilityPluginExtension extensio project .getDependencies() .create( - String.format( + Strings.format( "com.datadoghq:dd-javac-plugin:%s", extension.getCompilerPluginVersion())), project .getDependencies() .create( - String.format( + Strings.format( "com.datadoghq:dd-javac-plugin-client:%s", extension.getCompilerPluginVersion()))); diff --git a/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteQueryInfo.java b/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteQueryInfo.java index 391f63737cc..31de6fb7ba7 100644 --- a/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteQueryInfo.java +++ b/dd-java-agent/instrumentation/ignite-2.0/src/main/java/datadog/trace/instrumentation/ignite/v2/cache/IgniteQueryInfo.java @@ -8,6 +8,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.function.Function; @@ -80,7 +81,7 @@ public IgniteQueryInfo(String sql, String type) { boolean fragment = prospectiveOperation == null; // SQL fragment if not valid op this.operation = prospectiveOperation != null ? prospectiveOperation : DEFAULT_OPERATION; - if (HEALTH_CHECK_STATEMENTS.containsKey(sql.toUpperCase())) { + if (HEALTH_CHECK_STATEMENTS.containsKey(sql.toUpperCase(Locale.ROOT))) { // No need to mask health checks this.sql = HEALTH_CHECK_STATEMENTS.get(sql); @@ -136,7 +137,7 @@ public static String extractOperation(CharSequence sql) { } } if (firstWhitespace > -1) { - return sql.subSequence(start, firstWhitespace).toString().toUpperCase(); + return sql.subSequence(start, firstWhitespace).toString().toUpperCase(Locale.ROOT); } return null; } diff --git a/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/DBMCommentSizingBenchmark.java b/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/DBMCommentSizingBenchmark.java index 3d88c037e9e..eeb2047222b 100644 --- a/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/DBMCommentSizingBenchmark.java +++ b/dd-java-agent/instrumentation/jdbc/src/jmh/java/datadog/trace/instrumentation/jdbc/DBMCommentSizingBenchmark.java @@ -2,6 +2,7 @@ import datadog.trace.bootstrap.instrumentation.dbm.SQLCommenter; import datadog.trace.bootstrap.instrumentation.dbm.SharedDBCommenter; +import datadog.trace.util.Strings; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -65,9 +66,9 @@ public void setup() { scenario.equals("short_service") ? null : "00-12345678901234567890123456789012" - + String.format("%02x", i) + + Strings.format("%02x", i) + "-98765432109876" - + String.format("%02x", i) + + Strings.format("%02x", i) + "-01"; if (scenario.equals("long_full")) { services[i] = repeat("service", 80) + i; diff --git a/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisInstrumentation.java b/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisInstrumentation.java index 640497d7a85..bf9028a1c2e 100644 --- a/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisInstrumentation.java +++ b/dd-java-agent/instrumentation/jedis/jedis-3.0/src/main/java/datadog/trace/instrumentation/jedis30/JedisInstrumentation.java @@ -14,6 +14,7 @@ import datadog.trace.agent.tooling.InstrumenterModule; import datadog.trace.bootstrap.CallDepthThreadLocalMap; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import java.nio.charset.StandardCharsets; import net.bytebuddy.asm.Advice; import redis.clients.jedis.Connection; import redis.clients.jedis.Protocol; @@ -59,7 +60,7 @@ public static ContextScope onEnter( } else { // Protocol.Command is the only implementation in the Jedis lib as of 3.1 but this will save // us if that changes - DECORATE.onStatement(span, new String(command.getRaw())); + DECORATE.onStatement(span, new String(command.getRaw(), StandardCharsets.UTF_8)); } return activateSpan(span); } diff --git a/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/datadog/trace/instrumentation/jedis40/JedisInstrumentation.java b/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/datadog/trace/instrumentation/jedis40/JedisInstrumentation.java index 81d7c52a801..6d53695be82 100644 --- a/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/datadog/trace/instrumentation/jedis40/JedisInstrumentation.java +++ b/dd-java-agent/instrumentation/jedis/jedis-4.0/src/main/java/datadog/trace/instrumentation/jedis40/JedisInstrumentation.java @@ -14,6 +14,7 @@ import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import java.nio.charset.StandardCharsets; import net.bytebuddy.asm.Advice; import redis.clients.jedis.CommandObject; import redis.clients.jedis.Connection; @@ -61,7 +62,7 @@ public static ContextScope onEnter( } else { // Protocol.Command is the only implementation in the Jedis lib as of 3.1 but this will save // us if that changes - DECORATE.onStatement(span, new String(command.getRaw())); + DECORATE.onStatement(span, new String(command.getRaw(), StandardCharsets.UTF_8)); } return activateSpan(span); } diff --git a/dd-java-agent/instrumentation/junit/junit-4/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java b/dd-java-agent/instrumentation/junit/junit-4/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java index bba41f2463f..063ce684e19 100644 --- a/dd-java-agent/instrumentation/junit/junit-4/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java +++ b/dd-java-agent/instrumentation/junit/junit-4/junit-4.10/src/main/java/datadog/trace/instrumentation/junit4/TestEventsHandlerHolder.java @@ -9,6 +9,7 @@ import datadog.trace.util.ConcurrentEnumMap; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Collection; +import java.util.Locale; import java.util.Map; public abstract class TestEventsHandlerHolder { @@ -28,7 +29,7 @@ public static synchronized void start( HANDLERS.put( framework, InstrumentationBridge.createTestEventsHandler( - framework.name().toLowerCase(), null, null, capabilities)); + framework.name().toLowerCase(Locale.ROOT), null, null, capabilities)); } } diff --git a/dd-java-agent/instrumentation/junit/junit-5/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java b/dd-java-agent/instrumentation/junit/junit-5/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java index 1c8656a07cd..b3f447ecb57 100644 --- a/dd-java-agent/instrumentation/junit/junit-5/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java +++ b/dd-java-agent/instrumentation/junit/junit-5/junit-5.3/src/main/java/datadog/trace/instrumentation/junit5/TestEventsHandlerHolder.java @@ -9,6 +9,7 @@ import datadog.trace.bootstrap.ContextStore; import datadog.trace.util.ConcurrentEnumMap; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.util.Locale; import java.util.Map; import org.junit.platform.engine.TestDescriptor; import org.junit.platform.engine.TestEngine; @@ -60,7 +61,7 @@ public static synchronized void start( if (handler == null) { handler = InstrumentationBridge.createTestEventsHandler( - framework.name().toLowerCase(), + framework.name().toLowerCase(Locale.ROOT), suiteStore, testStore, JUnitPlatformUtils.capabilities(testEngine)); diff --git a/dd-java-agent/instrumentation/kafka/kafka-common/src/main/java/datadog/trace/instrumentation/kafka_common/Utils.java b/dd-java-agent/instrumentation/kafka/kafka-common/src/main/java/datadog/trace/instrumentation/kafka_common/Utils.java index d0f7eb4fcea..7a34edd2e6f 100644 --- a/dd-java-agent/instrumentation/kafka/kafka-common/src/main/java/datadog/trace/instrumentation/kafka_common/Utils.java +++ b/dd-java-agent/instrumentation/kafka/kafka-common/src/main/java/datadog/trace/instrumentation/kafka_common/Utils.java @@ -13,7 +13,8 @@ private Utils() {} // prevent instantiation DSM_TRANSACTION_SOURCE_READER = (source, headerName) -> { try { - return new String(((Headers) source).lastHeader(headerName).value()); + return new String( + ((Headers) source).lastHeader(headerName).value(), StandardCharsets.UTF_8); } catch (Throwable ignored) { return null; } diff --git a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/EmbeddingDecorator.java b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/EmbeddingDecorator.java index 5f223afcfc8..cee70ae7585 100644 --- a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/EmbeddingDecorator.java +++ b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/EmbeddingDecorator.java @@ -8,6 +8,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.api.Tags; import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; +import datadog.trace.util.Strings; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -77,7 +78,7 @@ public void withCreateEmbeddingResponse(AgentSpan span, CreateEmbeddingResponse firstEmbedding._embedding().asKnown().orElse(Collections.emptyList()).size(); span.setTag( CommonTags.OUTPUT, - String.format("[%d embedding(s) returned with size %d]", embeddingCount, embeddingSize)); + Strings.format("[%d embedding(s) returned with size %d]", embeddingCount, embeddingSize)); } } diff --git a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java index ef7031bb108..b0a4a958590 100644 --- a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java +++ b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/OpenAiDecorator.java @@ -21,6 +21,7 @@ import datadog.trace.bootstrap.instrumentation.api.UTF8BytesString; import datadog.trace.bootstrap.instrumentation.decorator.ClientDecorator; import java.util.List; +import java.util.Locale; import java.util.Map; import javax.annotation.Nonnull; @@ -63,7 +64,7 @@ public AgentSpan startSpan(ClientOptions clientOptions) { private String detectProvider(String baseUrl) { if (baseUrl != null) { - String lower = baseUrl.toLowerCase(); + String lower = baseUrl.toLowerCase(Locale.ROOT); if (lower.contains("azure")) return "azure_openai"; if (lower.contains("deepseek")) return "deepseek"; } diff --git a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/ResponseDecorator.java b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/ResponseDecorator.java index 82f4a44f025..9562c902d77 100644 --- a/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/ResponseDecorator.java +++ b/dd-java-agent/instrumentation/openai-java/openai-java-3.0/src/main/java/datadog/trace/instrumentation/openai_java/ResponseDecorator.java @@ -33,6 +33,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Optional; @@ -549,7 +550,7 @@ private void withResponse(AgentSpan span, Response response, boolean stream) { if (!metadata.containsKey("tool_choice")) { toolChoice .types() - .map(v -> v.type().toString().toLowerCase()) + .map(v -> v.type().toString().toLowerCase(Locale.ROOT)) .ifPresent(v -> metadata.put("tool_choice", v)); } if (!metadata.containsKey("tool_choice") && toolChoice.function().isPresent()) { diff --git a/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java b/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java index d0770c70f2a..e2e787ee543 100644 --- a/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java +++ b/dd-java-agent/instrumentation/spark/spark-common/src/main/java/datadog/trace/instrumentation/spark/AbstractDatadogSparkListener.java @@ -17,6 +17,7 @@ import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.SpanLink; import datadog.trace.util.AgentThreadFactory; +import datadog.trace.util.Strings; import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.PrintWriter; import java.io.StringWriter; @@ -33,6 +34,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Properties; @@ -593,7 +595,7 @@ public synchronized void onJobEnd(SparkListenerJobEnd jobEnd) { jobSpan.setTag(DDTags.ERROR_TYPE, "Spark Job Failed"); // Only propagate the error to the application if it is not a cancellation - if (errorMessage != null && !errorMessage.toLowerCase().contains("cancelled")) { + if (errorMessage != null && !errorMessage.toLowerCase(Locale.ROOT).contains("cancelled")) { lastJobFailed = true; lastJobFailedMessage = errorMessage; lastJobFailedStackTrace = errorStackTrace; @@ -826,7 +828,7 @@ private void sendTaskSpan( ExceptionFailure exceptionFailure = (ExceptionFailure) reason; taskSpan.setErrorMessage( - String.format("%s: %s", exceptionFailure.className(), exceptionFailure.description())); + Strings.format("%s: %s", exceptionFailure.className(), exceptionFailure.description())); taskSpan.setTag(DDTags.ERROR_STACK, exceptionFailure.fullStackTrace()); } else { taskSpan.setErrorMessage(reason.toErrorString()); @@ -1520,7 +1522,7 @@ private static void reportKafkaOffsets( } // check if this is a kafka source - if (progress.description().toLowerCase().startsWith("kafka")) { + if (progress.description().toLowerCase(Locale.ROOT).startsWith("kafka")) { try { // parse offsets from endOffsets json, reported in a format: // "topic" -> ["partition":value] diff --git a/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/datadog/trace/instrumentation/valkey/ValkeyInstrumentation.java b/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/datadog/trace/instrumentation/valkey/ValkeyInstrumentation.java index 07730c8d228..8b3f7402ea0 100644 --- a/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/datadog/trace/instrumentation/valkey/ValkeyInstrumentation.java +++ b/dd-java-agent/instrumentation/valkey-java-5.3/src/main/java/datadog/trace/instrumentation/valkey/ValkeyInstrumentation.java @@ -19,6 +19,7 @@ import io.valkey.Protocol; import io.valkey.ValkeyClientDecorator; import io.valkey.commands.ProtocolCommand; +import java.nio.charset.StandardCharsets; import net.bytebuddy.asm.Advice; @AutoService(InstrumenterModule.class) @@ -59,7 +60,7 @@ public static ContextScope onEnter( if (command instanceof Protocol.Command) { DECORATE.onStatement(span, ((Protocol.Command) command).name()); } else { - DECORATE.onStatement(span, new String(command.getRaw())); + DECORATE.onStatement(span, new String(command.getRaw(), StandardCharsets.UTF_8)); } return activateSpan(span); } diff --git a/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/CommandImplConstructorAdvice.java b/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/CommandImplConstructorAdvice.java index 839c62611cf..d54737f4b3e 100644 --- a/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/CommandImplConstructorAdvice.java +++ b/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/CommandImplConstructorAdvice.java @@ -5,6 +5,7 @@ import io.vertx.redis.client.Command; import io.vertx.redis.client.Redis; import io.vertx.redis.client.impl.CommandImpl; +import java.util.Locale; import net.bytebuddy.asm.Advice; public class CommandImplConstructorAdvice { @@ -12,7 +13,7 @@ public class CommandImplConstructorAdvice { public static void afterConstructor( @Advice.This final CommandImpl zis, @Advice.Argument(0) String command) { InstrumentationContext.get(Command.class, UTF8BytesString.class) - .put(zis, UTF8BytesString.create(command.toUpperCase())); + .put(zis, UTF8BytesString.create(command.toUpperCase(Locale.ROOT))); } private static void muzzleCheck() { diff --git a/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java b/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java index dec7fe39d02..1c4f7a76d4d 100644 --- a/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java +++ b/dd-java-agent/instrumentation/vertx/vertx-redis-client/vertx-redis-client-3.9/src/main/java/datadog/trace/instrumentation/vertx_redis_client/VertxRedisClientDecorator.java @@ -12,6 +12,7 @@ import datadog.trace.bootstrap.instrumentation.decorator.DBTypeProcessingDatabaseClientDecorator; import io.vertx.core.net.SocketAddress; import io.vertx.redis.client.Command; +import java.util.Locale; public class VertxRedisClientDecorator extends DBTypeProcessingDatabaseClientDecorator { @@ -71,7 +72,8 @@ protected String dbHostname(final SocketAddress socketAddress) { public AgentSpan startAndDecorateSpan(String command) { UTF8BytesString upperCase = - commandCache.computeIfAbsent(command, key -> UTF8BytesString.create(key.toUpperCase())); + commandCache.computeIfAbsent( + command, key -> UTF8BytesString.create(key.toUpperCase(Locale.ROOT))); return innerStartAndDecorateSpan(upperCase); } diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java index 0114503447c..1edd4fe3e90 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.jar.JarFile; @@ -176,7 +177,10 @@ static boolean getConfig(String configName) { case LIB_INJECTION_FORCE_SYS_PROP: { String envVarName = - LIB_INJECTION_FORCE_SYS_PROP.replace('.', '_').replace('-', '_').toUpperCase(); + LIB_INJECTION_FORCE_SYS_PROP + .replace('.', '_') + .replace('-', '_') + .toUpperCase(Locale.ROOT); String injectionForceFlag = EnvironmentVariables.get(envVarName); if (injectionForceFlag == null) { injectionForceFlag = SystemProperties.get(LIB_INJECTION_FORCE_SYS_PROP); @@ -376,7 +380,7 @@ static boolean shouldAbortDueToOtherJavaAgents() { // If there are 2 agents and one of them is for patching log4j, it's fine if (getAgentFilesFromVMArguments().size() == 2) { for (File agentFile : getAgentFilesFromVMArguments()) { - if (agentFile.getName().toLowerCase().contains("log4j")) { + if (agentFile.getName().toLowerCase(Locale.ROOT).contains("log4j")) { return false; } } diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index e9ea4fc7b7a..32ee6706b5a 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -151,7 +151,7 @@ private static String getAgentVersion() { return null; } - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); final StringBuilder sb = new StringBuilder(); for (int c = reader.read(); c != -1; c = reader.read()) { sb.append((char) c); diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/HttpProxy.java b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/HttpProxy.java index 63df85f3518..460797d6144 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/HttpProxy.java +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/server/http/HttpProxy.java @@ -11,6 +11,7 @@ import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; @@ -93,9 +94,10 @@ public Handler(Socket clientToProxy) { public void run() { try { BufferedReader clientToProxyIn = - new BufferedReader(new InputStreamReader(clientToProxy.getInputStream())); + new BufferedReader( + new InputStreamReader(clientToProxy.getInputStream(), StandardCharsets.ISO_8859_1)); OutputStreamWriter clientToProxyOut = - new OutputStreamWriter(clientToProxy.getOutputStream()); + new OutputStreamWriter(clientToProxy.getOutputStream(), StandardCharsets.ISO_8859_1); String requestString = clientToProxyIn.readLine(); System.out.println("Request Received " + requestString); diff --git a/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/server/http/JavaTestHttpServer.java b/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/server/http/JavaTestHttpServer.java index 1ff635fba5e..4762e9b10ea 100644 --- a/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/server/http/JavaTestHttpServer.java +++ b/dd-java-agent/testing/src/main/java/datadog/trace/agent/test/server/http/JavaTestHttpServer.java @@ -495,7 +495,7 @@ public byte[] getBody() { } public String getText() { - return new String(body); + return new String(body, StandardCharsets.UTF_8); } public String getParameter(String parameter) { diff --git a/dd-openfeature/src/main/java/com/datadog/openfeature/FlagEvalMetrics.java b/dd-openfeature/src/main/java/com/datadog/openfeature/FlagEvalMetrics.java index a108e0fd582..861b8c0475f 100644 --- a/dd-openfeature/src/main/java/com/datadog/openfeature/FlagEvalMetrics.java +++ b/dd-openfeature/src/main/java/com/datadog/openfeature/FlagEvalMetrics.java @@ -9,6 +9,7 @@ import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; import java.io.Closeable; +import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -132,10 +133,10 @@ void record( Attributes.builder() .put(ATTR_FLAG_KEY, flagKey) .put(ATTR_VARIANT, variant != null ? variant : "") - .put(ATTR_REASON, reason != null ? reason.toLowerCase() : "unknown"); + .put(ATTR_REASON, reason != null ? reason.toLowerCase(Locale.ROOT) : "unknown"); if (errorCode != null) { - builder.put(ATTR_ERROR_TYPE, errorCode.name().toLowerCase()); + builder.put(ATTR_ERROR_TYPE, errorCode.name().toLowerCase(Locale.ROOT)); } if (allocationKey != null && !allocationKey.isEmpty()) { diff --git a/dd-trace-api/src/main/java/datadog/trace/api/IdGenerationStrategy.java b/dd-trace-api/src/main/java/datadog/trace/api/IdGenerationStrategy.java index 34956222e3d..d7d124b533c 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/IdGenerationStrategy.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/IdGenerationStrategy.java @@ -3,6 +3,7 @@ import static java.lang.Long.MAX_VALUE; import java.security.SecureRandom; +import java.util.Locale; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.atomic.AtomicLong; @@ -33,7 +34,7 @@ public static IdGenerationStrategy fromName(String name) { } public static IdGenerationStrategy fromName(String name, boolean traceId128BitGenerationEnabled) { - switch (name.toUpperCase()) { + switch (name.toUpperCase(Locale.ROOT)) { case "RANDOM": return new Random(traceId128BitGenerationEnabled); case "SEQUENTIAL": diff --git a/dd-trace-api/src/main/java/datadog/trace/api/PropagationStyle.java b/dd-trace-api/src/main/java/datadog/trace/api/PropagationStyle.java index 89bdb67d1e5..06f7b8a31c8 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/PropagationStyle.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/PropagationStyle.java @@ -3,6 +3,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; /** * These are the old propagation styles that have been deprecated in favor of the propagation styles @@ -26,6 +27,6 @@ public List getNewStyles() { } public static PropagationStyle valueOfConfigName(String configName) { - return valueOf(configName.toUpperCase().trim()); + return valueOf(configName.toUpperCase(Locale.ROOT).trim()); } } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/TracePropagationStyle.java b/dd-trace-api/src/main/java/datadog/trace/api/TracePropagationStyle.java index af850871650..6f8f0649be5 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/TracePropagationStyle.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/TracePropagationStyle.java @@ -28,7 +28,7 @@ public enum TracePropagationStyle { NONE; public static TracePropagationStyle valueOfDisplayName(String displayName) { - String convertedName = displayName.toUpperCase().replace(' ', '_'); + String convertedName = displayName.toUpperCase(Locale.ROOT).replace(' ', '_'); // Another name for B3 for cross tracer compatibility switch (convertedName) { case "B3_SINGLE_HEADER": diff --git a/dd-trace-api/src/main/java/datadog/trace/api/internal/util/LongStringUtils.java b/dd-trace-api/src/main/java/datadog/trace/api/internal/util/LongStringUtils.java index f2196e8dadb..71d29c59115 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/internal/util/LongStringUtils.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/internal/util/LongStringUtils.java @@ -3,6 +3,7 @@ import static java.nio.charset.StandardCharsets.US_ASCII; import java.util.Arrays; +import java.util.Locale; /** * Utility class with common long decimal and hexadecimal parsing, and {@link String} creation @@ -90,7 +91,7 @@ public static long parseUnsignedLong(String s) throws NumberFormatException { char firstChar = s.charAt(0); if (firstChar == '-') { throw new NumberFormatException( - String.format("Illegal leading minus sign on unsigned string %s.", s)); + String.format(Locale.ROOT, "Illegal leading minus sign on unsigned string %s.", s)); } else { if (len <= 18) { // Signed 64 bits max is 19 digits, so this always fits return Long.parseLong(s); @@ -134,7 +135,7 @@ public static long parseUnsignedLong(String s) throws NumberFormatException { */ public static NumberFormatException numberFormatOutOfLongRange(CharSequence s) { return new NumberFormatException( - String.format("String value %s exceeds range of unsigned long.", s)); + String.format(Locale.ROOT, "String value %s exceeds range of unsigned long.", s)); } private static final byte[] HEX_DIGITS = { diff --git a/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java b/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java index e5b5a8efcf9..20016330c6a 100644 --- a/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java +++ b/dd-trace-api/src/test/java/datadog/trace/api/IdGenerationStrategyTest.java @@ -9,14 +9,39 @@ import java.security.SecureRandom; import java.util.HashSet; +import java.util.Locale; import java.util.Set; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.parallel.Resources; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.tabletest.junit.TableTest; class IdGenerationStrategyTest { + @Test + @ResourceLock(Resources.LOCALE) + void parseNamesWithTurkishDefaultLocale() { + Locale previous = Locale.getDefault(); + Locale previousFormat = Locale.getDefault(Locale.Category.FORMAT); + Locale previousDisplay = Locale.getDefault(Locale.Category.DISPLAY); + try { + Locale.setDefault(new Locale("tr", "TR")); + + assertNotNull(IdGenerationStrategy.fromName("sequential")); + assertEquals( + TracePropagationStyle.B3SINGLE, TracePropagationStyle.valueOfDisplayName("b3single")); + assertEquals( + TracePropagationStyle.B3SINGLE, + TracePropagationStyle.valueOfDisplayName("b3 single header")); + } finally { + Locale.setDefault(previous); + Locale.setDefault(Locale.Category.FORMAT, previousFormat); + Locale.setDefault(Locale.Category.DISPLAY, previousDisplay); + } + } + @TableTest({ "scenario | traceId128BitGenerationEnabled | strategyName ", "strategies-64-bit | false | {RANDOM, SEQUENTIAL, SECURE_RANDOM}", diff --git a/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/ExtractorBenchmark.java b/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/ExtractorBenchmark.java index a72be08a929..7e295a0eb33 100644 --- a/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/ExtractorBenchmark.java +++ b/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/ExtractorBenchmark.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Locale; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -122,7 +123,8 @@ private static String dup(String input) { // Just calling new String(string) is not good enough since it will copy the hash code // as well which will most likely need to be computed on a new header straight off the // wire - return new String(input.toLowerCase().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + return new String( + input.toLowerCase(Locale.ROOT).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); } private static List> resetList(List> list) { diff --git a/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/InjectorBenchmark.java b/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/InjectorBenchmark.java index 1c070167377..5d2a9f14ea9 100644 --- a/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/InjectorBenchmark.java +++ b/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/InjectorBenchmark.java @@ -16,6 +16,7 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import javax.annotation.ParametersAreNonnullByDefault; import org.openjdk.jmh.annotations.Benchmark; @@ -44,7 +45,8 @@ public class InjectorBenchmark { String injectPropagationStyles; static String dup(String input) { - return new String(input.toLowerCase().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); + return new String( + input.toLowerCase(Locale.ROOT).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); } Map headers; diff --git a/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/PropagationTagsBenchmark.java b/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/PropagationTagsBenchmark.java index cd2dcfc09dd..7e03359ecb5 100644 --- a/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/PropagationTagsBenchmark.java +++ b/dd-trace-core/src/jmh/java/datadog/trace/core/propagation/PropagationTagsBenchmark.java @@ -5,6 +5,7 @@ import de.thetaphi.forbiddenapis.SuppressForbidden; import java.util.Arrays; +import java.util.Locale; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -53,9 +54,9 @@ public class PropagationTagsBenchmark { public void setUp() { factory = PropagationTags.factory(); CharSequence[] parts = extractHeaderType.split("\\|"); - extractHT = PropagationTags.HeaderType.valueOf(((String) parts[0]).toUpperCase()); + extractHT = PropagationTags.HeaderType.valueOf(((String) parts[0]).toUpperCase(Locale.ROOT)); header = String.join(",", Arrays.stream(parts, 1, parts.length)::iterator); - injectHT = PropagationTags.HeaderType.valueOf(injectHeaderType.toUpperCase()); + injectHT = PropagationTags.HeaderType.valueOf(injectHeaderType.toUpperCase(Locale.ROOT)); } @Benchmark diff --git a/dd-trace-core/src/main/java/datadog/trace/common/sampling/RateByServiceTraceSampler.java b/dd-trace-core/src/main/java/datadog/trace/common/sampling/RateByServiceTraceSampler.java index c5601ebc5b4..326e8ac34cd 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/sampling/RateByServiceTraceSampler.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/sampling/RateByServiceTraceSampler.java @@ -10,6 +10,7 @@ import datadog.trace.common.writer.RemoteResponseListener; import datadog.trace.core.CoreSpan; import java.util.Collections; +import java.util.Locale; import java.util.Map; import java.util.TreeMap; import java.util.function.Function; @@ -254,8 +255,8 @@ public static EnvAndService fromString(String key) { private final String lowerService; private EnvAndService(String env, String service) { - lowerEnv = env.toLowerCase(); - lowerService = service.toLowerCase(); + lowerEnv = env.toLowerCase(Locale.ROOT); + lowerService = service.toLowerCase(Locale.ROOT); } boolean isFallback() { diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/FileBasedPayloadDispatcher.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/FileBasedPayloadDispatcher.java index dbed1cfe66e..1f3b2584572 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/FileBasedPayloadDispatcher.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/FileBasedPayloadDispatcher.java @@ -24,6 +24,7 @@ import datadog.trace.core.Metadata; import datadog.trace.core.MetadataConsumer; import datadog.trace.util.PidHelper; +import datadog.trace.util.Strings; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -330,7 +331,7 @@ private void writeFileAtomically(byte[] data) throws IOException { long pid = PidHelper.getPidAsLong(); long seq = sequence.getAndIncrement(); - String filename = String.format("%s-%d-%d-%d.json", filePrefix, timestampNs, pid, seq); + String filename = Strings.format("%s-%d-%d-%d.json", filePrefix, timestampNs, pid, seq); File target = new File(outputDir, filename); File tmp = new File(outputDir, filename + ".tmp"); diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDEvpProxyApi.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDEvpProxyApi.java index 9ec4eca5f4e..a6cf577cc3b 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDEvpProxyApi.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDEvpProxyApi.java @@ -11,6 +11,7 @@ import datadog.trace.api.intake.TrackType; import datadog.trace.common.writer.Payload; import datadog.trace.common.writer.RemoteApi; +import datadog.trace.util.Strings; import java.io.IOException; import java.net.ConnectException; import java.util.Locale; @@ -81,11 +82,11 @@ public DDEvpProxyApiBuilder compressionEnabled(boolean compressionEnabled) { public DDEvpProxyApi build() { final String trackName = trackType.name().toLowerCase(Locale.ROOT); - final String subdomain = String.format("%s-intake", trackName); + final String subdomain = Strings.format("%s-intake", trackName); final HttpUrl evpProxyUrl = agentUrl.resolve(evpProxyEndpoint); final HttpUrl proxiedApiUrl = - evpProxyUrl.resolve(String.format("api/%s/%s", apiVersion, trackName)); + evpProxyUrl.resolve(Strings.format("api/%s/%s", apiVersion, trackName)); final OkHttpClient client = (httpClient != null) diff --git a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDIntakeApi.java b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDIntakeApi.java index 7abad42d2f1..d7846294d69 100644 --- a/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDIntakeApi.java +++ b/dd-trace-core/src/main/java/datadog/trace/common/writer/ddintake/DDIntakeApi.java @@ -12,6 +12,7 @@ import datadog.trace.api.intake.TrackType; import datadog.trace.common.writer.Payload; import datadog.trace.common.writer.RemoteApi; +import datadog.trace.util.Strings; import java.io.IOException; import java.net.ConnectException; import java.util.Locale; @@ -87,9 +88,10 @@ public DDIntakeApi build() { final String trackName = (trackType != null ? trackType.name() : NOOP.name()).toLowerCase(Locale.ROOT); if (null == hostUrl) { - hostUrl = HttpUrl.get(String.format("https://%s-intake.%s", trackName, site)); + hostUrl = HttpUrl.get(Strings.format("https://%s-intake.%s", trackName, site)); } - final HttpUrl intakeUrl = hostUrl.resolve(String.format("/api/%s/%s", apiVersion, trackName)); + final HttpUrl intakeUrl = + hostUrl.resolve(Strings.format("/api/%s/%s", apiVersion, trackName)); final OkHttpClient client = (httpClient != null) ? httpClient : OkHttpUtils.buildHttpClient(intakeUrl, timeoutMillis); diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/HaystackHttpCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/HaystackHttpCodec.java index bc3b7bc14f0..d02c710ba71 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/HaystackHttpCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/HaystackHttpCodec.java @@ -12,6 +12,7 @@ import datadog.trace.api.TracePropagationStyle; import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.core.DDSpanContext; +import datadog.trace.util.Strings; import de.thetaphi.forbiddenapis.SuppressForbidden; import java.util.Map; import java.util.TreeMap; @@ -263,7 +264,7 @@ private static String convertLongToUUID(long id) { // ones. // this is done for the purpose of being able to maintain cardinality and idempotence of the // conversion - String idHex = String.format("%016x", id); + String idHex = Strings.format("%016x", id); return DATADOG + "-" + idHex.substring(0, 4) + "-" + idHex.substring(4); } diff --git a/dd-trace-core/src/main/java/datadog/trace/core/propagation/XRayHttpCodec.java b/dd-trace-core/src/main/java/datadog/trace/core/propagation/XRayHttpCodec.java index 1060e706b89..50d5b35bf34 100644 --- a/dd-trace-core/src/main/java/datadog/trace/core/propagation/XRayHttpCodec.java +++ b/dd-trace-core/src/main/java/datadog/trace/core/propagation/XRayHttpCodec.java @@ -17,6 +17,7 @@ import datadog.trace.api.TracePropagationStyle; import datadog.trace.api.sampling.PrioritySampling; import datadog.trace.core.DDSpanContext; +import datadog.trace.util.Strings; import java.util.Map; import java.util.function.Supplier; import org.slf4j.Logger; @@ -74,7 +75,7 @@ public void inject(DDSpanContext context, C carrier, CarrierSetter setter new StringBuilder() .append(ROOT_PREFIX) .append( - String.format( + Strings.format( "%08x", e2eStart > 0 ? NANOSECONDS.toSeconds(e2eStart) diff --git a/gradle/forbiddenApiFilters/main.txt b/gradle/forbiddenApiFilters/main.txt index d8ddd91df36..4490816ac9b 100644 --- a/gradle/forbiddenApiFilters/main.txt +++ b/gradle/forbiddenApiFilters/main.txt @@ -7,9 +7,6 @@ java.lang.String#split(java.lang.String,int) java.lang.String#replaceAll(java.lang.String,java.lang.String) java.lang.String#replaceFirst(java.lang.String,java.lang.String) -# uses the platform's default charset, which may not be UTF-8 -java.lang.String#getBytes() - # can initialize java.util.logging when ACCP is installed, prefer RandomUtils instead java.util.UUID#randomUUID() @@ -63,3 +60,81 @@ java.io.ObjectInputStream#readObject() @defaultMessage Do not use OkHostnameVerifier directly — it is an internal OkHttp class. Use the normal OkHttp connection flow via HttpUrl (CVE-2021-0341) okhttp3.internal.tls.OkHostnameVerifier datadog.okhttp3.internal.tls.OkHostnameVerifier + +# Require explicit charsets and locales. Keep this subset of jdk-unsafe focused on +# encoding and formatting; the bundled rules also forbid default time zones. +# Use @SuppressForbidden on the smallest scope with a comment explaining intentional defaults. +# https://github.com/policeman-tools/forbidden-apis/wiki/BundledSignatures +@defaultMessage Pass an explicit charset (usually StandardCharsets.UTF_8); explain intentional defaults beside @SuppressForbidden. +java.lang.String#getBytes() +java.lang.String#(byte[]) +java.lang.String#(byte[],int,int) +java.io.ByteArrayOutputStream#toString() +java.io.FileReader#(java.io.File) +java.io.FileReader#(java.io.FileDescriptor) +java.io.FileReader#(java.lang.String) +java.io.FileWriter#(java.io.File) +java.io.FileWriter#(java.io.File,boolean) +java.io.FileWriter#(java.io.FileDescriptor) +java.io.FileWriter#(java.lang.String) +java.io.FileWriter#(java.lang.String,boolean) +java.io.InputStreamReader#(java.io.InputStream) +java.io.OutputStreamWriter#(java.io.OutputStream) +java.io.PrintStream#(java.io.File) +java.io.PrintStream#(java.io.OutputStream) +java.io.PrintStream#(java.io.OutputStream,boolean) +java.io.PrintStream#(java.lang.String) +java.io.PrintWriter#(java.io.File) +java.io.PrintWriter#(java.io.OutputStream) +java.io.PrintWriter#(java.io.OutputStream,boolean) +java.io.PrintWriter#(java.lang.String) +java.net.URLDecoder#decode(java.lang.String) +java.net.URLEncoder#encode(java.lang.String) +java.util.Scanner#(java.io.File) +java.util.Scanner#(java.io.InputStream) +java.util.Scanner#(java.nio.channels.ReadableByteChannel) +java.util.Scanner#(java.nio.file.Path) + +@defaultMessage Pass an explicit locale (usually Locale.ROOT); explain intentional defaults beside @SuppressForbidden. +java.lang.String#toLowerCase() +java.lang.String#toUpperCase() +java.lang.String#format(java.lang.String,java.lang.Object[]) +java.lang.String#formatted(java.lang.Object[]) +java.io.PrintStream#format(java.lang.String,java.lang.Object[]) +java.io.PrintStream#printf(java.lang.String,java.lang.Object[]) +java.io.PrintWriter#format(java.lang.String,java.lang.Object[]) +java.io.PrintWriter#printf(java.lang.String,java.lang.Object[]) +java.util.Formatter#() +java.util.Formatter#(java.lang.Appendable) +java.util.Formatter#(java.io.File) +java.util.Formatter#(java.io.File,java.lang.String) +java.util.Formatter#(java.io.OutputStream) +java.util.Formatter#(java.io.OutputStream,java.lang.String) +java.util.Formatter#(java.io.PrintStream) +java.util.Formatter#(java.lang.String) +java.util.Formatter#(java.lang.String,java.lang.String) +java.util.Formatter#format(java.lang.String,java.lang.Object[]) +java.text.SimpleDateFormat#() +java.text.SimpleDateFormat#(java.lang.String) +java.text.DateFormatSymbols#() +java.text.DateFormatSymbols#getInstance() +java.text.DecimalFormat#() +java.text.DecimalFormat#(java.lang.String) +java.text.DecimalFormatSymbols#() +java.text.DecimalFormatSymbols#getInstance() +java.text.MessageFormat#(java.lang.String) +java.text.MessageFormat#format(java.lang.String,java.lang.Object[]) +java.text.NumberFormat#getInstance() +java.text.NumberFormat#getNumberInstance() +java.text.NumberFormat#getIntegerInstance() +java.text.NumberFormat#getCurrencyInstance() +java.text.NumberFormat#getPercentInstance() +java.text.DateFormat#getInstance() +java.text.DateFormat#getDateInstance() +java.text.DateFormat#getDateInstance(int) +java.text.DateFormat#getTimeInstance() +java.text.DateFormat#getTimeInstance(int) +java.text.DateFormat#getDateTimeInstance() +java.text.DateFormat#getDateTimeInstance(int,int) +java.time.format.DateTimeFormatter#ofPattern(java.lang.String) +java.time.format.DateTimeFormatterBuilder#toFormatter() diff --git a/internal-api/src/jmh/java/datadog/trace/util/CaseInsensitiveMapBenchmark.java b/internal-api/src/jmh/java/datadog/trace/util/CaseInsensitiveMapBenchmark.java index c72a26430af..95a25d4e0d7 100644 --- a/internal-api/src/jmh/java/datadog/trace/util/CaseInsensitiveMapBenchmark.java +++ b/internal-api/src/jmh/java/datadog/trace/util/CaseInsensitiveMapBenchmark.java @@ -1,6 +1,7 @@ package datadog.trace.util; import java.util.HashMap; +import java.util.Locale; import java.util.Random; import java.util.TreeMap; import java.util.function.Supplier; @@ -81,7 +82,7 @@ static T init(Supplier supplier) { () -> { String[] upperPrefixes = new String[PREFIXES.length]; for (int i = 0; i < PREFIXES.length; ++i) { - upperPrefixes[i] = PREFIXES[i].toUpperCase(); + upperPrefixes[i] = PREFIXES[i].toUpperCase(Locale.ROOT); } return upperPrefixes; }); @@ -101,7 +102,7 @@ static T init(Supplier supplier) { int suffixIndex = curRandom.nextInt(NUM_SUFFIXES + 1); String key = PREFIXES[prefixIndex] + "-" + suffixIndex; - keys[i] = toUpper ? key.toUpperCase() : key.toLowerCase(); + keys[i] = toUpper ? key.toUpperCase(Locale.ROOT) : key.toLowerCase(Locale.ROOT); } return keys; }); @@ -160,13 +161,13 @@ static HashMap _create_hashMap() { for (int suffix = 0; suffix < NUM_SUFFIXES; ++suffix) { for (String prefix : PREFIXES) { map.put( - (prefix + "-" + suffix).toLowerCase(), + (prefix + "-" + suffix).toLowerCase(Locale.ROOT), suffix); // arguable, but real caller probably doesn't know the case ahead-of-time } } for (int suffix = 0; suffix < NUM_SUFFIXES; suffix += 2) { for (String prefix : UPPER_PREFIXES) { - map.put((prefix + "-" + suffix).toLowerCase(), suffix + 1); + map.put((prefix + "-" + suffix).toLowerCase(Locale.ROOT), suffix + 1); } } return map; @@ -178,7 +179,7 @@ static HashMap _create_hashMap() { public Integer lookup_hashMap() { // This benchmark is still "correct" in multi-threaded context, // Map is populated under the class initialization lock and not changed thereafter - return HASH_MAP.get(nextLookupKey().toLowerCase()); + return HASH_MAP.get(nextLookupKey().toLowerCase(Locale.ROOT)); } @Benchmark 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 83fc85c38dd..f1770897a82 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -798,6 +798,7 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.UnknownHostException; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Files; @@ -6542,7 +6543,10 @@ static String initHostName() { try (final TraceScope scope = AgentTracer.get().muteTracing(); final BufferedReader reader = new BufferedReader( - new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream()))) { + // The native hostname command uses the platform encoding. + new InputStreamReader( + Runtime.getRuntime().exec("hostname").getInputStream(), + Charset.defaultCharset()))) { possibleHostname = reader.readLine(); } catch (final Throwable ignore) { // Ignore. Hostname command is not always available diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Command.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Command.java index 5ea133cb7e3..8869eb0430f 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Command.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Command.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** The type of Git command that was executed. */ public enum Command implements TagValue { @@ -19,7 +20,7 @@ public enum Command implements TagValue { private final String s; Command() { - s = "command:" + name().toLowerCase(); + s = "command:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/CoverageErrorType.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/CoverageErrorType.java index 3f4bf6c17f2..27ed17c7761 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/CoverageErrorType.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/CoverageErrorType.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** The type of coverage collection error */ public enum CoverageErrorType implements TagValue { @@ -11,7 +12,7 @@ public enum CoverageErrorType implements TagValue { private final String s; CoverageErrorType() { - s = "error_type:" + name().toLowerCase(); + s = "error_type:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EarlyFlakeDetectionAbortReason.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EarlyFlakeDetectionAbortReason.java index e47313ea206..f88353d918b 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EarlyFlakeDetectionAbortReason.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EarlyFlakeDetectionAbortReason.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; public enum EarlyFlakeDetectionAbortReason implements TagValue { FAULTY, @@ -9,7 +10,7 @@ public enum EarlyFlakeDetectionAbortReason implements TagValue { private final String s; EarlyFlakeDetectionAbortReason() { - s = "early_flake_detection_abort_reason:" + name().toLowerCase(); + s = "early_flake_detection_abort_reason:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Endpoint.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Endpoint.java index 529644493b2..bf407846169 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Endpoint.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Endpoint.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** The type of endpoint where a request is sent */ public enum Endpoint implements TagValue { @@ -11,7 +12,7 @@ public enum Endpoint implements TagValue { private final String s; Endpoint() { - s = "endpoint:" + name().toLowerCase(); + s = "endpoint:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/ErrorType.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/ErrorType.java index cacbfa73705..3df3cf35ae3 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/ErrorType.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/ErrorType.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** The type of HTTP request error */ public enum ErrorType implements TagValue { @@ -12,7 +13,7 @@ public enum ErrorType implements TagValue { private final String s; ErrorType() { - s = "error_type:" + name().toLowerCase(); + s = "error_type:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EventType.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EventType.java index 2e327c234e0..b0515d0fd1f 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EventType.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/EventType.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** The type of test event */ public enum EventType implements TagValue { @@ -12,7 +13,7 @@ public enum EventType implements TagValue { private final String s; EventType() { - s = "event_type:" + name().toLowerCase(); + s = "event_type:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderDiscrepant.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderDiscrepant.java index e356805a255..892434ebdea 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderDiscrepant.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderDiscrepant.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; public enum GitProviderDiscrepant implements TagValue { USER_SUPPLIED, @@ -11,6 +12,6 @@ public enum GitProviderDiscrepant implements TagValue { @Override public String asString() { - return "discrepant_provider:" + name().toLowerCase(); + return "discrepant_provider:" + name().toLowerCase(Locale.ROOT); } } diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderExpected.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderExpected.java index cf2c6e5b9f3..6e2c426ed6c 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderExpected.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitProviderExpected.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; public enum GitProviderExpected implements TagValue { USER_SUPPLIED, @@ -11,6 +12,6 @@ public enum GitProviderExpected implements TagValue { @Override public String asString() { - return "expected_provider:" + name().toLowerCase(); + return "expected_provider:" + name().toLowerCase(Locale.ROOT); } } diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaDiscrepancyType.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaDiscrepancyType.java index 2be69a41e08..d6c0289e0f4 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaDiscrepancyType.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaDiscrepancyType.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; public enum GitShaDiscrepancyType implements TagValue { REPOSITORY_DISCREPANCY, @@ -8,6 +9,6 @@ public enum GitShaDiscrepancyType implements TagValue { @Override public String asString() { - return "type:" + name().toLowerCase(); + return "type:" + name().toLowerCase(Locale.ROOT); } } diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaMatch.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaMatch.java index f5ea9b9a7f8..d4270aa8d5d 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaMatch.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/GitShaMatch.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; public enum GitShaMatch implements TagValue { TRUE, @@ -8,6 +9,6 @@ public enum GitShaMatch implements TagValue { @Override public String asString() { - return "matched:" + name().toLowerCase(); + return "matched:" + name().toLowerCase(Locale.ROOT); } } diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Library.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Library.java index 62eca84ad1b..d28429bf07a 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Library.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Library.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** The type of code-coverage library used */ public enum Library implements TagValue { @@ -10,7 +11,7 @@ public enum Library implements TagValue { private final String s; Library() { - s = "library:" + name().toLowerCase(); + s = "library:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Provider.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Provider.java index ae71b1c2bd2..9bf50420505 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Provider.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/Provider.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** What kind of CI provider is running the test session. */ public enum Provider implements TagValue { @@ -25,7 +26,7 @@ public enum Provider implements TagValue { private final String s; Provider() { - s = "provider:" + name().toLowerCase(); + s = "provider:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/SkipReason.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/SkipReason.java index 0457b3a6067..25ff539979e 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/SkipReason.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/SkipReason.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; public enum SkipReason implements TagValue { ITR("Skipped by Datadog Test Impact Analysis"), @@ -11,7 +12,7 @@ public enum SkipReason implements TagValue { SkipReason(String description) { this.description = description; - this.s = "skip_reason:" + name().toLowerCase(); + this.s = "skip_reason:" + name().toLowerCase(Locale.ROOT); } public String getDescription() { diff --git a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/TestFrameworkInstrumentation.java b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/TestFrameworkInstrumentation.java index eedbaed7e80..908c933369c 100644 --- a/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/TestFrameworkInstrumentation.java +++ b/internal-api/src/main/java/datadog/trace/api/civisibility/telemetry/tag/TestFrameworkInstrumentation.java @@ -1,6 +1,7 @@ package datadog.trace.api.civisibility.telemetry.tag; import datadog.trace.api.civisibility.telemetry.TagValue; +import java.util.Locale; /** The name of test framework instrumentation used */ public enum TestFrameworkInstrumentation implements TagValue { @@ -18,7 +19,7 @@ public enum TestFrameworkInstrumentation implements TagValue { private final String s; TestFrameworkInstrumentation() { - s = "test_framework:" + name().toLowerCase(); + s = "test_framework:" + name().toLowerCase(Locale.ROOT); } @Override diff --git a/internal-api/src/main/java/datadog/trace/api/gateway/InferredProxySpan.java b/internal-api/src/main/java/datadog/trace/api/gateway/InferredProxySpan.java index 2c19b0772e3..14d701ca95c 100644 --- a/internal-api/src/main/java/datadog/trace/api/gateway/InferredProxySpan.java +++ b/internal-api/src/main/java/datadog/trace/api/gateway/InferredProxySpan.java @@ -22,6 +22,7 @@ import datadog.trace.bootstrap.instrumentation.api.http.DatadogServerUrl; import datadog.trace.bootstrap.instrumentation.api.http.HttpServerUrl; import datadog.trace.bootstrap.instrumentation.api.http.OtelServerUrl; +import datadog.trace.util.Strings; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -208,7 +209,7 @@ String computeArn(String proxySystem, String region, String apiId) { return null; // Unknown proxy type } - return String.format("arn:%s:apigateway:%s::/%s/%s", partition, region, resourceType, apiId); + return Strings.format("arn:%s:apigateway:%s::/%s/%s", partition, region, resourceType, apiId); } /** diff --git a/internal-api/src/main/java/datadog/trace/api/git/PersonInfo.java b/internal-api/src/main/java/datadog/trace/api/git/PersonInfo.java index 2eae5d9c6c9..d3bd596f94e 100644 --- a/internal-api/src/main/java/datadog/trace/api/git/PersonInfo.java +++ b/internal-api/src/main/java/datadog/trace/api/git/PersonInfo.java @@ -3,6 +3,7 @@ import datadog.trace.util.Strings; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.Locale; import java.util.Objects; import java.util.TimeZone; @@ -112,7 +113,7 @@ private static String buildISO8601Date(final long when) { return null; } - final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_ISO8601); + final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT_ISO8601, Locale.ROOT); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); return sdf.format(new Date(when)); } diff --git a/internal-api/src/main/java/datadog/trace/api/intake/Intake.java b/internal-api/src/main/java/datadog/trace/api/intake/Intake.java index 2d715c2913a..6f4dbb1d46e 100644 --- a/internal-api/src/main/java/datadog/trace/api/intake/Intake.java +++ b/internal-api/src/main/java/datadog/trace/api/intake/Intake.java @@ -1,6 +1,7 @@ package datadog.trace.api.intake; import datadog.trace.api.Config; +import datadog.trace.util.Strings; import java.util.function.Function; public enum Intake { @@ -53,10 +54,10 @@ public boolean isAgentlessEnabled(Config config) { public String getAgentlessUrl(Config config) { String custom = customUrl.apply(config); if (custom != null && !custom.isEmpty()) { - return String.format("%s/api/%s/", custom, version); + return Strings.format("%s/api/%s/", custom, version); } else { String site = config.getSite(); - return String.format("https://%s.%s/api/%s/", urlPrefix, site, version); + return Strings.format("https://%s.%s/api/%s/", urlPrefix, site, version); } } } diff --git a/internal-api/src/main/java/datadog/trace/api/profiling/ProfilingEnablement.java b/internal-api/src/main/java/datadog/trace/api/profiling/ProfilingEnablement.java index 4c1131f8ade..a3904210417 100644 --- a/internal-api/src/main/java/datadog/trace/api/profiling/ProfilingEnablement.java +++ b/internal-api/src/main/java/datadog/trace/api/profiling/ProfilingEnablement.java @@ -2,6 +2,7 @@ import datadog.trace.api.config.ProfilingConfig; import datadog.trace.bootstrap.config.provider.ConfigProvider; +import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,7 +19,7 @@ public enum ProfilingEnablement { ProfilingEnablement(boolean active) { this.active = active; - this.alias = this.name().toLowerCase(); + this.alias = this.name().toLowerCase(Locale.ROOT); } ProfilingEnablement(boolean active, String alias) { @@ -51,7 +52,7 @@ public static ProfilingEnablement of(String value) { if (value == null) { return DISABLED; } - switch (value.toLowerCase()) { + switch (value.toLowerCase(Locale.ROOT)) { case "true": case "1": return ENABLED; @@ -66,7 +67,7 @@ public static void validate(String value) { if (value == null) { return; } - switch (value.toLowerCase()) { + switch (value.toLowerCase(Locale.ROOT)) { case "false": case "true": case "auto": diff --git a/internal-api/src/main/java/datadog/trace/api/telemetry/Endpoint.java b/internal-api/src/main/java/datadog/trace/api/telemetry/Endpoint.java index ded841404c4..ddc37e4dce6 100644 --- a/internal-api/src/main/java/datadog/trace/api/telemetry/Endpoint.java +++ b/internal-api/src/main/java/datadog/trace/api/telemetry/Endpoint.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -151,7 +152,7 @@ static , C extends Collection> List parseMethods(fi } final List result = new ArrayList<>(methods.size()); for (E value : methods) { - final String methodName = value.name().toUpperCase(); + final String methodName = value.name().toUpperCase(Locale.ROOT); if (METHODS.contains(value.name())) { result.add(methodName); } diff --git a/internal-api/src/main/java/datadog/trace/logging/LogLevel.java b/internal-api/src/main/java/datadog/trace/logging/LogLevel.java index 7fb8ab5981f..10e7972d524 100644 --- a/internal-api/src/main/java/datadog/trace/logging/LogLevel.java +++ b/internal-api/src/main/java/datadog/trace/logging/LogLevel.java @@ -1,5 +1,7 @@ package datadog.trace.logging; +import java.util.Locale; + /** Log level enum. */ public enum LogLevel { TRACE, @@ -18,7 +20,7 @@ public enum LogLevel { * @return the corresponding {@link LogLevel} enum */ public static LogLevel fromString(String level) { - String upper = level.toUpperCase(); + String upper = level.toUpperCase(Locale.ROOT); try { return Enum.valueOf(LogLevel.class, upper); } catch (Throwable t) { diff --git a/internal-api/src/main/java/datadog/trace/util/Strings.java b/internal-api/src/main/java/datadog/trace/util/Strings.java index 7bd2055f32c..6b08fd29e71 100644 --- a/internal-api/src/main/java/datadog/trace/util/Strings.java +++ b/internal-api/src/main/java/datadog/trace/util/Strings.java @@ -8,6 +8,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.Iterator; +import java.util.Locale; import java.util.NoSuchElementException; import java.util.concurrent.ThreadLocalRandom; import javax.annotation.Nullable; @@ -18,6 +19,11 @@ public final class Strings { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + /** Formats text with {@link Locale#ROOT}. */ + public static String format(String format, Object... args) { + return String.format(Locale.ROOT, format, args); + } + /** com.foo.Bar -> com/foo/Bar.class */ public static String getResourceName(final String className) { if (!className.endsWith(".class")) { diff --git a/internal-api/src/test/java/datadog/trace/util/StringsTest.java b/internal-api/src/test/java/datadog/trace/util/StringsTest.java index 8d3348de980..42fe1bc9a89 100644 --- a/internal-api/src/test/java/datadog/trace/util/StringsTest.java +++ b/internal-api/src/test/java/datadog/trace/util/StringsTest.java @@ -5,15 +5,33 @@ import static org.junit.jupiter.params.provider.Arguments.arguments; import java.security.NoSuchAlgorithmException; +import java.util.Locale; import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.ResourceLock; +import org.junit.jupiter.api.parallel.Resources; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import org.tabletest.junit.TableTest; class StringsTest { + @ParameterizedTest + @ValueSource(strings = {"de-DE", "tr-TR"}) + @ResourceLock(Resources.LOCALE) + void formatWithRootLocale(String languageTag) { + Locale previous = Locale.getDefault(Locale.Category.FORMAT); + try { + Locale.setDefault(Locale.Category.FORMAT, Locale.forLanguageTag(languageTag)); + + assertEquals("IDENTIFIER: 1,234.50", Strings.format("%S: %,.2f", "identifier", 1234.5)); + } finally { + Locale.setDefault(Locale.Category.FORMAT, previous); + } + } + @TableTest({ "scenario | className | expected ", "dotted class name | 'foo.bar.Class' | 'foo/bar/Class.class'", diff --git a/products/metrics/metrics-lib/src/main/java/datadog/metrics/impl/statsd/DDAgentStatsDClient.java b/products/metrics/metrics-lib/src/main/java/datadog/metrics/impl/statsd/DDAgentStatsDClient.java index 8f319cdef91..d7cf6120f56 100644 --- a/products/metrics/metrics-lib/src/main/java/datadog/metrics/impl/statsd/DDAgentStatsDClient.java +++ b/products/metrics/metrics-lib/src/main/java/datadog/metrics/impl/statsd/DDAgentStatsDClient.java @@ -3,6 +3,7 @@ import com.timgroup.statsd.Event; import com.timgroup.statsd.ServiceCheck; import datadog.metrics.api.statsd.StatsDClient; +import java.util.Locale; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -91,7 +92,7 @@ public void serviceCheck( @Override public void recordEvent( String type, String source, String eventName, String message, String... tags) { - Event.AlertType alertType = Event.AlertType.valueOf(type.toUpperCase()); + Event.AlertType alertType = Event.AlertType.valueOf(type.toUpperCase(Locale.ROOT)); Event.Builder eventBuilder = Event.builder() .withTitle(eventName) diff --git a/remote-config/remote-config-core/src/main/java/datadog/remoteconfig/DefaultConfigurationPoller.java b/remote-config/remote-config-core/src/main/java/datadog/remoteconfig/DefaultConfigurationPoller.java index 76ef06740b7..076e3a5101d 100644 --- a/remote-config/remote-config-core/src/main/java/datadog/remoteconfig/DefaultConfigurationPoller.java +++ b/remote-config/remote-config-core/src/main/java/datadog/remoteconfig/DefaultConfigurationPoller.java @@ -22,6 +22,7 @@ import datadog.trace.util.AgentTaskScheduler; import datadog.trace.util.AgentThreadFactory; import datadog.trace.util.SizeCheckedInputStream; +import datadog.trace.util.Strings; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -474,9 +475,9 @@ private String buildErrorMessage(List errors) { } StringBuilder aggregateMessage = new StringBuilder(); aggregateMessage.append( - String.format("Failed to apply configuration due to %d errors:%n", errors.size())); + Strings.format("Failed to apply configuration due to %d errors:%n", errors.size())); for (int i = 0; i < errors.size(); i++) { - aggregateMessage.append(String.format(" (%d) %s%n", i + 1, errors.get(i).getMessage())); + aggregateMessage.append(Strings.format(" (%d) %s%n", i + 1, errors.get(i).getMessage())); } return aggregateMessage.toString(); } diff --git a/telemetry/src/main/java/datadog/telemetry/FileBasedTelemetryClient.java b/telemetry/src/main/java/datadog/telemetry/FileBasedTelemetryClient.java index 83bd1ed1352..22d9d163ef9 100644 --- a/telemetry/src/main/java/datadog/telemetry/FileBasedTelemetryClient.java +++ b/telemetry/src/main/java/datadog/telemetry/FileBasedTelemetryClient.java @@ -1,6 +1,7 @@ package datadog.telemetry; import datadog.trace.util.PidHelper; +import datadog.trace.util.Strings; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -76,7 +77,7 @@ private static byte[] readBody(Request request) throws IOException { private void writeFileAtomically(byte[] data) throws IOException { long seq = sequence.getAndIncrement(); String pid = PidHelper.getPid(); - String filename = String.format("telemetry-%020d-%s.json", seq, pid); + String filename = Strings.format("telemetry-%020d-%s.json", seq, pid); File target = new File(outputDir, filename); File tmp = new File(outputDir, filename + ".tmp"); diff --git a/telemetry/src/main/java/datadog/telemetry/dependency/Dependency.java b/telemetry/src/main/java/datadog/telemetry/dependency/Dependency.java index 6765f77f4de..42929784165 100644 --- a/telemetry/src/main/java/datadog/telemetry/dependency/Dependency.java +++ b/telemetry/src/main/java/datadog/telemetry/dependency/Dependency.java @@ -1,5 +1,6 @@ package datadog.telemetry.dependency; +import datadog.trace.util.Strings; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.io.InputStream; @@ -222,7 +223,7 @@ public static synchronized Dependency guessFallbackNoPom( md.reset(); is = new DigestInputStream(is, md); while (is.read(buf, 0, buf.length) > 0) {} - hash = String.format("%040X", new BigInteger(1, md.digest())); + hash = Strings.format("%040X", new BigInteger(1, md.digest())); } log.debug("No maven dependency added {}.{} jar name {} hash {}", name, version, source, hash); return new Dependency(name, version, source, hash); diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java index f8187b546d2..bcf9508bd28 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/ConfigProvider.java @@ -624,6 +624,7 @@ private static Properties loadConfigurationFile(ConfigProvider configProvider) { return properties; } + // Retain the platform encoding for existing configuration files. try (final FileReader fileReader = new FileReader(configurationFile)) { properties.load(fileReader); } catch (final FileNotFoundException fnf) { diff --git a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/civisibility/CiEnvironmentVariables.java b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/civisibility/CiEnvironmentVariables.java index c8208ee709e..2ac00061349 100644 --- a/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/civisibility/CiEnvironmentVariables.java +++ b/utils/config-utils/src/main/java/datadog/trace/bootstrap/config/provider/civisibility/CiEnvironmentVariables.java @@ -11,6 +11,7 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.concurrent.Callable; @@ -125,7 +126,8 @@ private static Map getRemoteEnvironment(String url, String key) new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8))) { String body = r.lines().collect(Collectors.joining("\n")); throw new IOException( - String.format("Remote environment request failed (HTTP %d) %s", code, body)); + String.format( + Locale.ROOT, "Remote environment request failed (HTTP %d) %s", code, body)); } } diff --git a/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java b/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java index 61d174e97c5..605ccad868e 100644 --- a/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java +++ b/utils/container-utils/src/main/java/datadog/common/container/ContainerInfo.java @@ -3,6 +3,7 @@ import de.thetaphi.forbiddenapis.SuppressForbidden; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -231,7 +232,7 @@ public static ContainerInfo fromDefaultProcFile() throws IOException, ParseExcep } static ContainerInfo fromProcFile(Path path) throws IOException, ParseException { - final String content = new String(Files.readAllBytes(path)); + final String content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8); if (content.isEmpty()) { log.debug("Proc file is empty"); return new ContainerInfo(); diff --git a/utils/test-utils/src/main/java/datadog/trace/test/util/PollingConditions.java b/utils/test-utils/src/main/java/datadog/trace/test/util/PollingConditions.java index 654bcc758b7..a498ffe4ec7 100644 --- a/utils/test-utils/src/main/java/datadog/trace/test/util/PollingConditions.java +++ b/utils/test-utils/src/main/java/datadog/trace/test/util/PollingConditions.java @@ -2,6 +2,7 @@ import datadog.trace.api.internal.VisibleForTesting; import datadog.trace.test.util.ThreadUtils.ThrowingRunnable; +import java.util.Locale; /** * A small Java port of Spock's {@code spock.util.concurrent.PollingConditions}. It repeatedly @@ -112,8 +113,10 @@ public void within(double seconds, ThrowingRunnable conditions) { } throw new AssertionError( String.format( + Locale.ROOT, "Condition not satisfied after %1.2f seconds and %d attempts", - elapsed / 1000d, attempts), + elapsed / 1000d, + attempts), lastFailure); } diff --git a/utils/version-utils/src/main/java/datadog/common/version/VersionInfo.java b/utils/version-utils/src/main/java/datadog/common/version/VersionInfo.java index eb6829883b6..96e605407ff 100644 --- a/utils/version-utils/src/main/java/datadog/common/version/VersionInfo.java +++ b/utils/version-utils/src/main/java/datadog/common/version/VersionInfo.java @@ -4,6 +4,7 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +23,8 @@ public class VersionInfo { final InputStream is = VersionInfo.class.getClassLoader().getResourceAsStream("version-utils.version"); if (is != null) { - final BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + final BufferedReader reader = + new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); final StringBuilder sb = new StringBuilder(); final char[] buffer = new char[1 << 8]; int read;