From 067bbb78ef50fef5e53b85d257cd93b765bc9e73 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Fri, 21 Mar 2025 16:27:11 +0100 Subject: [PATCH 1/3] Add support for filtering shaded third-party libs Add filtering on shading identifiers Add option to add more shading idententifiers --- .../debugger/agent/ThirdPartyLibraries.java | 23 +++++++++++++++ .../symbol/SymbolExtractionTransformer.java | 3 +- .../debugger/util/ClassNameFiltering.java | 28 +++++++++++++++---- .../agent/ThirdPartyLibrariesTest.java | 21 +++++++++++++- .../debugger/symbol/SymDBEnablementTest.java | 3 +- .../SymbolExtractionTransformerTest.java | 3 +- .../debugger/util/ClassNameFilteringTest.java | 18 +++++++----- .../trace/api/config/DebuggerConfig.java | 1 + .../main/java/datadog/trace/api/Config.java | 7 +++++ 9 files changed, 91 insertions(+), 16 deletions(-) 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 1f5b9d1d30e..aabee3b67ba 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,10 +7,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,6 +24,20 @@ public class ThirdPartyLibraries { private static final JsonAdapter ADAPTER = new Moshi.Builder().build().adapter(InternalConfig.class); private static final String FILE_NAME = "/third_party_libraries.json"; + private static final Set DEFAULT_SHADING_IDENTIFIERS = + new HashSet<>( + Arrays.asList( + "shaded", + "thirdparty", + "dependencies", + "relocated", + "bundled", + "embedded", + "vendor", + "repackaged", + "shadow", + "shim", + "wrapper")); private ThirdPartyLibraries() {} @@ -46,6 +62,13 @@ public Set getThirdPartyExcludes(Config config) { .collect(Collectors.toSet()); } + public Set getShadingIdentifiers(Config config) { + Stream configStream = + config.getThirdPartyShadingIdentifiers().stream().filter(s -> !s.isEmpty()); + return Stream.concat(configStream, DEFAULT_SHADING_IDENTIFIERS.stream()) + .collect(Collectors.toSet()); + } + // Add a*, b*, c*, ..., z* to the exclude trie in ClassNameFiltering. Simply adding * does not // work. private static Set getExcludeAll() { diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolExtractionTransformer.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolExtractionTransformer.java index 2d1ac86c87f..0d7b4503c8f 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolExtractionTransformer.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolExtractionTransformer.java @@ -1,6 +1,7 @@ package com.datadog.debugger.symbol; import datadog.trace.bootstrap.debugger.DebuggerContext.ClassNameFilter; +import datadog.trace.util.Strings; import java.lang.instrument.ClassFileTransformer; import java.security.ProtectionDomain; import org.slf4j.Logger; @@ -34,7 +35,7 @@ public byte[] transform( // Don't parse our own classes to avoid duplicate class definition return null; } - if (classNameFiltering.isExcluded(className)) { + if (classNameFiltering.isExcluded(Strings.getClassName(className))) { return null; } symbolAggregator.parseClass(className, classfileBuffer, protectionDomain); diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java index 7722746d3da..964d35e2c95 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java @@ -4,6 +4,7 @@ import datadog.trace.api.Config; import datadog.trace.bootstrap.debugger.DebuggerContext.ClassNameFilter; import datadog.trace.util.ClassNameTrie; +import datadog.trace.util.Strings; import java.util.Collections; import java.util.Set; import java.util.regex.Pattern; @@ -14,36 +15,53 @@ public class ClassNameFiltering implements ClassNameFilter { private final ClassNameTrie includeTrie; private final ClassNameTrie excludeTrie; + private final Set shadingIdentifiers; public ClassNameFiltering(Config config) { this( ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(config), - ThirdPartyLibraries.INSTANCE.getThirdPartyExcludes(config)); + ThirdPartyLibraries.INSTANCE.getThirdPartyExcludes(config), + ThirdPartyLibraries.INSTANCE.getShadingIdentifiers(config)); } public ClassNameFiltering(Set excludes) { - this(excludes, Collections.emptySet()); + this(excludes, Collections.emptySet(), Collections.emptySet()); } - public ClassNameFiltering(Set excludes, Set includes) { + public ClassNameFiltering( + Set excludes, Set includes, Set shadingIdentifiers) { ClassNameTrie.Builder excludeBuilder = new ClassNameTrie.Builder(); excludes.forEach(s -> excludeBuilder.put(s + "*", 1)); this.excludeTrie = excludeBuilder.buildTrie(); ClassNameTrie.Builder includeBuilder = new ClassNameTrie.Builder(); includes.forEach(s -> includeBuilder.put(s + "*", 1)); this.includeTrie = includeBuilder.buildTrie(); + this.shadingIdentifiers = shadingIdentifiers; } + // className is the fully qualified class name with '.' (Java type) notation public boolean isExcluded(String className) { return (includeTrie.apply(className) < 0 && excludeTrie.apply(className) > 0) - || isLambdaProxyClass(className); + || isLambdaProxyClass(className) + || isShaded(className); } static boolean isLambdaProxyClass(String className) { return LAMBDA_PROXY_CLASS_PATTERN.matcher(className).matches(); } + boolean isShaded(String className) { + String packageName = Strings.getPackageName(className); + for (String shadingIdentifier : shadingIdentifiers) { + if (packageName.contains(shadingIdentifier)) { + return true; + } + } + return false; + } + public static ClassNameFiltering allowAll() { - return new ClassNameFiltering(Collections.emptySet(), Collections.emptySet()); + return new ClassNameFiltering( + Collections.emptySet(), Collections.emptySet(), Collections.emptySet()); } } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/ThirdPartyLibrariesTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/ThirdPartyLibrariesTest.java index e57315df152..01abb157469 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/ThirdPartyLibrariesTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/ThirdPartyLibrariesTest.java @@ -1,5 +1,6 @@ package com.datadog.debugger.agent; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -20,6 +21,7 @@ class ThirdPartyLibrariesTest { void setUp() { when(mockConfig.getThirdPartyIncludes()).thenReturn(Collections.emptySet()); when(mockConfig.getThirdPartyExcludes()).thenReturn(Collections.emptySet()); + when(mockConfig.getThirdPartyShadingIdentifiers()).thenReturn(Collections.emptySet()); } @Test @@ -29,7 +31,6 @@ void testGetExcludesContainsDefaultExclude() { @Test void testGetExcludesWithExplicitExclude() { - when(mockConfig.getThirdPartyIncludes()) .thenReturn(Collections.singleton("com.datadog.debugger")); assertTrue( @@ -72,4 +73,22 @@ void testGetExcludeAll() { Set excludeAll = ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(null); for (char c : ThirdPartyLibraries.ALPHABET) assertTrue(excludeAll.contains(String.valueOf(c))); } + + @Test + void testEmptyStrings() { + int expectedIncludeDefaultSize = + ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(mockConfig).size(); + int expectedShadingDefaultSize = + ThirdPartyLibraries.INSTANCE.getShadingIdentifiers(mockConfig).size(); + when(mockConfig.getThirdPartyIncludes()).thenReturn(Collections.singleton("")); + when(mockConfig.getThirdPartyExcludes()).thenReturn(Collections.singleton("")); + when(mockConfig.getThirdPartyShadingIdentifiers()).thenReturn(Collections.singleton("")); + assertEquals( + expectedIncludeDefaultSize, + ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(mockConfig).size()); + assertTrue(ThirdPartyLibraries.INSTANCE.getThirdPartyExcludes(mockConfig).isEmpty()); + assertEquals( + expectedShadingDefaultSize, + ThirdPartyLibraries.INSTANCE.getShadingIdentifiers(mockConfig).size()); + } } diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java index c5fefef7534..4a59215c0ed 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java @@ -169,7 +169,8 @@ public void noDuplicateSymbolExtraction() { ClassNameFiltering classNameFiltering = new ClassNameFiltering( Collections.singleton("org.springframework."), - Collections.singleton("com.datadog.debugger.")); + Collections.singleton("com.datadog.debugger."), + Collections.emptySet()); SymbolAggregator symbolAggregator = new SymbolAggregator(classNameFiltering, mockSymbolSink, 1); SymDBEnablement symDBEnablement = new SymDBEnablement(instr, config, symbolAggregator, classNameFiltering); diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolExtractionTransformerTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolExtractionTransformerTest.java index bffb1748292..86da95d19a4 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolExtractionTransformerTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolExtractionTransformerTest.java @@ -982,7 +982,8 @@ private SymbolExtractionTransformer createTransformer( return createTransformer( symbolSink, symbolFlushThreshold, - new ClassNameFiltering(TRANSFORMER_EXCLUDES, Collections.singleton(SYMBOL_PACKAGE))); + new ClassNameFiltering( + TRANSFORMER_EXCLUDES, Collections.singleton(SYMBOL_PACKAGE), Collections.emptySet())); } private SymbolExtractionTransformer createTransformer( diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java index bc5dec14c99..b4f339a4abf 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java @@ -6,7 +6,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import com.datadog.debugger.agent.ThirdPartyLibraries; import datadog.trace.api.Config; import java.util.Collections; import java.util.HashSet; @@ -52,7 +51,8 @@ public void testIncludeOverridesExclude() { ClassNameFiltering classNameFiltering = new ClassNameFiltering( Collections.singleton("com.datadog.debugger"), - Collections.singleton("com.datadog.debugger")); + Collections.singleton("com.datadog.debugger"), + Collections.emptySet()); assertFalse(classNameFiltering.isExcluded("com.datadog.debugger.FooBar")); } @@ -60,7 +60,9 @@ public void testIncludeOverridesExclude() { public void testIncludePrefixOverridesExclude() { ClassNameFiltering classNameFiltering = new ClassNameFiltering( - Collections.singleton("com.datadog.debugger"), Collections.singleton("com.datadog")); + Collections.singleton("com.datadog.debugger"), + Collections.singleton("com.datadog"), + Collections.emptySet()); assertFalse(classNameFiltering.isExcluded("com.datadog.debugger.FooBar")); } @@ -69,7 +71,8 @@ public void testIncludeSomeExcludeSome() { ClassNameFiltering classNameFiltering = new ClassNameFiltering( Stream.of("com.datadog.debugger", "org.junit").collect(Collectors.toSet()), - Collections.singleton("com.datadog.debugger")); + Collections.singleton("com.datadog.debugger"), + Collections.emptySet()); assertFalse(classNameFiltering.isExcluded("com.datadog.debugger.FooBar")); assertTrue(classNameFiltering.isExcluded("org.junit.FooBar")); } @@ -82,14 +85,15 @@ public void testIncludeSomeExcludeSome() { "akka.Actor", "cats.Functor", "org.junit.jupiter.api.Test", - "org.datadog.jmxfetch.FooBar" + "org.datadog.jmxfetch.FooBar", + "shaded.org.junit.Test" }) public void testExcludeDefaults(String input) { Config config = mock(Config.class); when(config.getThirdPartyExcludes()).thenReturn(Collections.emptySet()); when(config.getThirdPartyIncludes()).thenReturn(Collections.emptySet()); - ClassNameFiltering classNameFiltering = - new ClassNameFiltering(ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(config)); + when(config.getThirdPartyShadingIdentifiers()).thenReturn(Collections.emptySet()); + ClassNameFiltering classNameFiltering = new ClassNameFiltering(config); assertTrue(classNameFiltering.isExcluded(input)); } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java index 5b2e32ad62e..58b90fa4e69 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java @@ -61,6 +61,7 @@ public final class DebuggerConfig { public static final String DISTRIBUTED_DEBUGGER_ENABLED = "distributed.debugger.enabled"; public static final String THIRD_PARTY_INCLUDES = "third.party.includes"; public static final String THIRD_PARTY_EXCLUDES = "third.party.excludes"; + public static final String THIRD_PARTY_SHADING_IDENTIFIERS = "third.party.shading.identifiers"; private DebuggerConfig() {} } 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 fd7eca95403..5e0f1b786b9 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -430,6 +430,7 @@ public static String getHostName() { private final Set debuggerThirdPartyIncludes; private final Set debuggerThirdPartyExcludes; + private final Set debuggerShadingIdentifiers; private final boolean awsPropagationEnabled; private final boolean sqsPropagationEnabled; @@ -1734,6 +1735,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) debuggerThirdPartyIncludes = tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_INCLUDES)); debuggerThirdPartyExcludes = tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_EXCLUDES)); + debuggerShadingIdentifiers = + tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_SHADING_IDENTIFIERS)); awsPropagationEnabled = isPropagationEnabled(true, "aws", "aws-sdk"); sqsPropagationEnabled = isPropagationEnabled(true, "sqs"); @@ -3299,6 +3302,10 @@ public Set getThirdPartyExcludes() { return debuggerThirdPartyExcludes; } + public Set getThirdPartyShadingIdentifiers() { + return debuggerShadingIdentifiers; + } + private String getFinalDebuggerBaseUrl() { if (agentUrl.startsWith("unix:")) { // provide placeholder agent URL, in practice we'll be tunnelling over UDS From d511e34bec7dbf62fc33cc844b3df2d92358fef0 Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Tue, 25 Mar 2025 16:34:17 +0100 Subject: [PATCH 2/3] fix shaded detection --- .../debugger/util/ClassNameFiltering.java | 31 +++++++++------ .../debugger/util/ClassNameFilteringTest.java | 18 ++++++++- .../datadog/trace/util/ClassNameTrie.java | 18 ++++++++- .../trace/util/ClassNameTrieTest.groovy | 39 +++++++++++++++++++ 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java index 964d35e2c95..771792a1bf9 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java @@ -4,7 +4,6 @@ import datadog.trace.api.Config; import datadog.trace.bootstrap.debugger.DebuggerContext.ClassNameFilter; import datadog.trace.util.ClassNameTrie; -import datadog.trace.util.Strings; import java.util.Collections; import java.util.Set; import java.util.regex.Pattern; @@ -15,7 +14,7 @@ public class ClassNameFiltering implements ClassNameFilter { private final ClassNameTrie includeTrie; private final ClassNameTrie excludeTrie; - private final Set shadingIdentifiers; + private final ClassNameTrie shadingTrie; public ClassNameFiltering(Config config) { this( @@ -36,28 +35,36 @@ public ClassNameFiltering( ClassNameTrie.Builder includeBuilder = new ClassNameTrie.Builder(); includes.forEach(s -> includeBuilder.put(s + "*", 1)); this.includeTrie = includeBuilder.buildTrie(); - this.shadingIdentifiers = shadingIdentifiers; + ClassNameTrie.Builder shadingBuilder = new ClassNameTrie.Builder(); + shadingIdentifiers.forEach(s -> shadingBuilder.put(s + "*", 1)); + this.shadingTrie = shadingBuilder.buildTrie(); } // className is the fully qualified class name with '.' (Java type) notation public boolean isExcluded(String className) { - return (includeTrie.apply(className) < 0 && excludeTrie.apply(className) > 0) - || isLambdaProxyClass(className) - || isShaded(className); + int shadedIdx = shadedIndexOf(className); + shadedIdx = Math.max(shadedIdx, 0); + return (includeTrie.apply(className, shadedIdx) < 0 + && excludeTrie.apply(className, shadedIdx) > 0) + || isLambdaProxyClass(className); } static boolean isLambdaProxyClass(String className) { return LAMBDA_PROXY_CLASS_PATTERN.matcher(className).matches(); } - boolean isShaded(String className) { - String packageName = Strings.getPackageName(className); - for (String shadingIdentifier : shadingIdentifiers) { - if (packageName.contains(shadingIdentifier)) { - return true; + int shadedIndexOf(String className) { + String current = className; + int idx = 0; + int previousIdx = 0; + while ((idx = current.indexOf('.', previousIdx)) > 0) { + if (shadingTrie.apply(current, previousIdx) > 0) { + return idx + 1; } + idx++; + previousIdx = idx; } - return false; + return -1; } public static ClassNameFiltering allowAll() { diff --git a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java index b4f339a4abf..6fdf52764a7 100644 --- a/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java +++ b/dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java @@ -7,6 +7,7 @@ import static org.mockito.Mockito.when; import datadog.trace.api.Config; +import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -85,8 +86,7 @@ public void testIncludeSomeExcludeSome() { "akka.Actor", "cats.Functor", "org.junit.jupiter.api.Test", - "org.datadog.jmxfetch.FooBar", - "shaded.org.junit.Test" + "org.datadog.jmxfetch.FooBar" }) public void testExcludeDefaults(String input) { Config config = mock(Config.class); @@ -97,6 +97,20 @@ public void testExcludeDefaults(String input) { assertTrue(classNameFiltering.isExcluded(input)); } + @Test + public void testShaded() { + Config config = mock(Config.class); + when(config.getThirdPartyExcludes()).thenReturn(Collections.emptySet()); + when(config.getThirdPartyIncludes()) + .thenReturn(new HashSet<>(Arrays.asList("com.google", "org.junit"))); + when(config.getThirdPartyShadingIdentifiers()).thenReturn(Collections.emptySet()); + ClassNameFiltering classNameFiltering = new ClassNameFiltering(config); + assertTrue(classNameFiltering.isExcluded("com.google.FooBar")); + assertTrue(classNameFiltering.isExcluded("shaded.com.google.FooBar")); + assertFalse(classNameFiltering.isExcluded("com.example.shaded.com.example.FooBar")); + assertTrue(classNameFiltering.isExcluded("com.example.shaded.com.google.FooBar")); + } + @Test void lambdaProxyClasses() { // jdk8: at diff --git a/internal-api/src/main/java/datadog/trace/util/ClassNameTrie.java b/internal-api/src/main/java/datadog/trace/util/ClassNameTrie.java index 1e7e43ebef9..eff49449fa2 100644 --- a/internal-api/src/main/java/datadog/trace/util/ClassNameTrie.java +++ b/internal-api/src/main/java/datadog/trace/util/ClassNameTrie.java @@ -117,9 +117,17 @@ public int apply(String key) { return apply(trieData, longJumps, key); } + public int apply(String key, int fromIndex) { + return apply(trieData, longJumps, key, fromIndex); + } + public static int apply(char[] data, int[] longJumps, String key) { + return apply(data, longJumps, key, 0); + } + + public static int apply(char[] data, int[] longJumps, String key, int fromIndex) { int keyLength = key.length(); - int keyIndex = 0; + int keyIndex = fromIndex; int dataIndex = 0; int result = -1; @@ -840,6 +848,14 @@ private static void generateJavaFile( } lines.add(" }"); lines.add(""); + lines.add(" public static int apply(String key, int fromIndex) {"); + if (hasLongJumps) { + lines.add(" return ClassNameTrie.apply(TRIE_DATA, LONG_JUMPS, key, fromIndex);"); + } else { + lines.add(" return ClassNameTrie.apply(TRIE_DATA, null, key, fromIndex);"); + } + lines.add(" }"); + lines.add(""); lines.add(" private " + className + "() {}"); lines.add("}"); Files.write(javaPath, lines, StandardCharsets.UTF_8); diff --git a/internal-api/src/test/groovy/datadog/trace/util/ClassNameTrieTest.groovy b/internal-api/src/test/groovy/datadog/trace/util/ClassNameTrieTest.groovy index 6ac2cbf87b0..3440856bc70 100644 --- a/internal-api/src/test/groovy/datadog/trace/util/ClassNameTrieTest.groovy +++ b/internal-api/src/test/groovy/datadog/trace/util/ClassNameTrieTest.groovy @@ -44,6 +44,45 @@ class ClassNameTrieTest extends DDSpecification { // spotless:on } + def 'test class name "#key" mapping with fromIndex'() { + when: + int value = TestClassNamesTrie.apply(key, "garbage.".length()) + then: + value == expected + where: + // spotless:off + key | expected + 'garbage.One' | 1 + 'garbage.com.Two' | 2 + 'garbage.com.foo.Three' | 3 + 'garbage.company.foo.Four' | 4 + 'garbage.com.foobar.Five' | 5 + 'garbage.company.foobar.Six' | 6 + 'garbage.company.foobar.Sixty' | 60 + 'garbage.com.f' | 7 + 'garbage.com.foo.a' | 8 + 'garbage.com.foobar.b' | 9 + 'garbage.company.f' | 10 + 'garbage.company.foo.a' | 11 + 'garbage.company.foobar.S' | 12 + 'garbage.com.Two$f' | 13 + 'garbage.foobar.Two$b' | 14 + 'garbage.' | -1 + 'garbage.O' | -1 + 'garbage._' | -1 + 'garbage.On' | -1 + 'garbage.O_' | -1 + 'garbage.On_' | -1 + 'garbage.OneNoMatch' | -1 + 'garbage.com.Twos' | 7 + 'garbage.com.foo.Threes' | 8 + 'garbage.com.foobar.Fives' | 9 + 'garbage.foobar.Thre' | -1 + 'garbage.foobar.Three' | 15 + 'garbage.foobar.ThreeMore' | 15 + // spotless:on + } + def 'test internal name "#key" mapping'() { when: int value = TestClassNamesTrie.apply(key) From c7e292e360905d599042ace5568d5a36d307c8fd Mon Sep 17 00:00:00 2001 From: jean-philippe bempel Date: Tue, 25 Mar 2025 16:41:52 +0100 Subject: [PATCH 3/3] remove unused var --- .../java/com/datadog/debugger/util/ClassNameFiltering.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java index 771792a1bf9..316c9152181 100644 --- a/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java +++ b/dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java @@ -54,11 +54,10 @@ static boolean isLambdaProxyClass(String className) { } int shadedIndexOf(String className) { - String current = className; int idx = 0; int previousIdx = 0; - while ((idx = current.indexOf('.', previousIdx)) > 0) { - if (shadingTrie.apply(current, previousIdx) > 0) { + while ((idx = className.indexOf('.', previousIdx)) > 0) { + if (shadingTrie.apply(className, previousIdx) > 0) { return idx + 1; } idx++;