Skip to content

Commit 067bbb7

Browse files
committed
Add support for filtering shaded third-party libs
Add filtering on shading identifiers Add option to add more shading idententifiers
1 parent fe1d6d6 commit 067bbb7

File tree

9 files changed

+91
-16
lines changed

9 files changed

+91
-16
lines changed

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/agent/ThirdPartyLibraries.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
import java.io.IOException;
88
import java.io.InputStream;
99
import java.io.InputStreamReader;
10+
import java.util.Arrays;
1011
import java.util.HashSet;
1112
import java.util.List;
1213
import java.util.Set;
1314
import java.util.stream.Collectors;
15+
import java.util.stream.Stream;
1416
import org.slf4j.Logger;
1517
import org.slf4j.LoggerFactory;
1618

@@ -22,6 +24,20 @@ public class ThirdPartyLibraries {
2224
private static final JsonAdapter<InternalConfig> ADAPTER =
2325
new Moshi.Builder().build().adapter(InternalConfig.class);
2426
private static final String FILE_NAME = "/third_party_libraries.json";
27+
private static final Set<String> DEFAULT_SHADING_IDENTIFIERS =
28+
new HashSet<>(
29+
Arrays.asList(
30+
"shaded",
31+
"thirdparty",
32+
"dependencies",
33+
"relocated",
34+
"bundled",
35+
"embedded",
36+
"vendor",
37+
"repackaged",
38+
"shadow",
39+
"shim",
40+
"wrapper"));
2541

2642
private ThirdPartyLibraries() {}
2743

@@ -46,6 +62,13 @@ public Set<String> getThirdPartyExcludes(Config config) {
4662
.collect(Collectors.toSet());
4763
}
4864

65+
public Set<String> getShadingIdentifiers(Config config) {
66+
Stream<String> configStream =
67+
config.getThirdPartyShadingIdentifiers().stream().filter(s -> !s.isEmpty());
68+
return Stream.concat(configStream, DEFAULT_SHADING_IDENTIFIERS.stream())
69+
.collect(Collectors.toSet());
70+
}
71+
4972
// Add a*, b*, c*, ..., z* to the exclude trie in ClassNameFiltering. Simply adding * does not
5073
// work.
5174
private static Set<String> getExcludeAll() {

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/symbol/SymbolExtractionTransformer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.datadog.debugger.symbol;
22

33
import datadog.trace.bootstrap.debugger.DebuggerContext.ClassNameFilter;
4+
import datadog.trace.util.Strings;
45
import java.lang.instrument.ClassFileTransformer;
56
import java.security.ProtectionDomain;
67
import org.slf4j.Logger;
@@ -34,7 +35,7 @@ public byte[] transform(
3435
// Don't parse our own classes to avoid duplicate class definition
3536
return null;
3637
}
37-
if (classNameFiltering.isExcluded(className)) {
38+
if (classNameFiltering.isExcluded(Strings.getClassName(className))) {
3839
return null;
3940
}
4041
symbolAggregator.parseClass(className, classfileBuffer, protectionDomain);

dd-java-agent/agent-debugger/src/main/java/com/datadog/debugger/util/ClassNameFiltering.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import datadog.trace.api.Config;
55
import datadog.trace.bootstrap.debugger.DebuggerContext.ClassNameFilter;
66
import datadog.trace.util.ClassNameTrie;
7+
import datadog.trace.util.Strings;
78
import java.util.Collections;
89
import java.util.Set;
910
import java.util.regex.Pattern;
@@ -14,36 +15,53 @@ public class ClassNameFiltering implements ClassNameFilter {
1415

1516
private final ClassNameTrie includeTrie;
1617
private final ClassNameTrie excludeTrie;
18+
private final Set<String> shadingIdentifiers;
1719

1820
public ClassNameFiltering(Config config) {
1921
this(
2022
ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(config),
21-
ThirdPartyLibraries.INSTANCE.getThirdPartyExcludes(config));
23+
ThirdPartyLibraries.INSTANCE.getThirdPartyExcludes(config),
24+
ThirdPartyLibraries.INSTANCE.getShadingIdentifiers(config));
2225
}
2326

2427
public ClassNameFiltering(Set<String> excludes) {
25-
this(excludes, Collections.emptySet());
28+
this(excludes, Collections.emptySet(), Collections.emptySet());
2629
}
2730

28-
public ClassNameFiltering(Set<String> excludes, Set<String> includes) {
31+
public ClassNameFiltering(
32+
Set<String> excludes, Set<String> includes, Set<String> shadingIdentifiers) {
2933
ClassNameTrie.Builder excludeBuilder = new ClassNameTrie.Builder();
3034
excludes.forEach(s -> excludeBuilder.put(s + "*", 1));
3135
this.excludeTrie = excludeBuilder.buildTrie();
3236
ClassNameTrie.Builder includeBuilder = new ClassNameTrie.Builder();
3337
includes.forEach(s -> includeBuilder.put(s + "*", 1));
3438
this.includeTrie = includeBuilder.buildTrie();
39+
this.shadingIdentifiers = shadingIdentifiers;
3540
}
3641

42+
// className is the fully qualified class name with '.' (Java type) notation
3743
public boolean isExcluded(String className) {
3844
return (includeTrie.apply(className) < 0 && excludeTrie.apply(className) > 0)
39-
|| isLambdaProxyClass(className);
45+
|| isLambdaProxyClass(className)
46+
|| isShaded(className);
4047
}
4148

4249
static boolean isLambdaProxyClass(String className) {
4350
return LAMBDA_PROXY_CLASS_PATTERN.matcher(className).matches();
4451
}
4552

53+
boolean isShaded(String className) {
54+
String packageName = Strings.getPackageName(className);
55+
for (String shadingIdentifier : shadingIdentifiers) {
56+
if (packageName.contains(shadingIdentifier)) {
57+
return true;
58+
}
59+
}
60+
return false;
61+
}
62+
4663
public static ClassNameFiltering allowAll() {
47-
return new ClassNameFiltering(Collections.emptySet(), Collections.emptySet());
64+
return new ClassNameFiltering(
65+
Collections.emptySet(), Collections.emptySet(), Collections.emptySet());
4866
}
4967
}

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/ThirdPartyLibrariesTest.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.datadog.debugger.agent;
22

3+
import static org.junit.jupiter.api.Assertions.assertEquals;
34
import static org.junit.jupiter.api.Assertions.assertFalse;
45
import static org.junit.jupiter.api.Assertions.assertNotNull;
56
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -20,6 +21,7 @@ class ThirdPartyLibrariesTest {
2021
void setUp() {
2122
when(mockConfig.getThirdPartyIncludes()).thenReturn(Collections.emptySet());
2223
when(mockConfig.getThirdPartyExcludes()).thenReturn(Collections.emptySet());
24+
when(mockConfig.getThirdPartyShadingIdentifiers()).thenReturn(Collections.emptySet());
2325
}
2426

2527
@Test
@@ -29,7 +31,6 @@ void testGetExcludesContainsDefaultExclude() {
2931

3032
@Test
3133
void testGetExcludesWithExplicitExclude() {
32-
3334
when(mockConfig.getThirdPartyIncludes())
3435
.thenReturn(Collections.singleton("com.datadog.debugger"));
3536
assertTrue(
@@ -72,4 +73,22 @@ void testGetExcludeAll() {
7273
Set<String> excludeAll = ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(null);
7374
for (char c : ThirdPartyLibraries.ALPHABET) assertTrue(excludeAll.contains(String.valueOf(c)));
7475
}
76+
77+
@Test
78+
void testEmptyStrings() {
79+
int expectedIncludeDefaultSize =
80+
ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(mockConfig).size();
81+
int expectedShadingDefaultSize =
82+
ThirdPartyLibraries.INSTANCE.getShadingIdentifiers(mockConfig).size();
83+
when(mockConfig.getThirdPartyIncludes()).thenReturn(Collections.singleton(""));
84+
when(mockConfig.getThirdPartyExcludes()).thenReturn(Collections.singleton(""));
85+
when(mockConfig.getThirdPartyShadingIdentifiers()).thenReturn(Collections.singleton(""));
86+
assertEquals(
87+
expectedIncludeDefaultSize,
88+
ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(mockConfig).size());
89+
assertTrue(ThirdPartyLibraries.INSTANCE.getThirdPartyExcludes(mockConfig).isEmpty());
90+
assertEquals(
91+
expectedShadingDefaultSize,
92+
ThirdPartyLibraries.INSTANCE.getShadingIdentifiers(mockConfig).size());
93+
}
7594
}

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymDBEnablementTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ public void noDuplicateSymbolExtraction() {
169169
ClassNameFiltering classNameFiltering =
170170
new ClassNameFiltering(
171171
Collections.singleton("org.springframework."),
172-
Collections.singleton("com.datadog.debugger."));
172+
Collections.singleton("com.datadog.debugger."),
173+
Collections.emptySet());
173174
SymbolAggregator symbolAggregator = new SymbolAggregator(classNameFiltering, mockSymbolSink, 1);
174175
SymDBEnablement symDBEnablement =
175176
new SymDBEnablement(instr, config, symbolAggregator, classNameFiltering);

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/symbol/SymbolExtractionTransformerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,8 @@ private SymbolExtractionTransformer createTransformer(
982982
return createTransformer(
983983
symbolSink,
984984
symbolFlushThreshold,
985-
new ClassNameFiltering(TRANSFORMER_EXCLUDES, Collections.singleton(SYMBOL_PACKAGE)));
985+
new ClassNameFiltering(
986+
TRANSFORMER_EXCLUDES, Collections.singleton(SYMBOL_PACKAGE), Collections.emptySet()));
986987
}
987988

988989
private SymbolExtractionTransformer createTransformer(

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/util/ClassNameFilteringTest.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import static org.mockito.Mockito.mock;
77
import static org.mockito.Mockito.when;
88

9-
import com.datadog.debugger.agent.ThirdPartyLibraries;
109
import datadog.trace.api.Config;
1110
import java.util.Collections;
1211
import java.util.HashSet;
@@ -52,15 +51,18 @@ public void testIncludeOverridesExclude() {
5251
ClassNameFiltering classNameFiltering =
5352
new ClassNameFiltering(
5453
Collections.singleton("com.datadog.debugger"),
55-
Collections.singleton("com.datadog.debugger"));
54+
Collections.singleton("com.datadog.debugger"),
55+
Collections.emptySet());
5656
assertFalse(classNameFiltering.isExcluded("com.datadog.debugger.FooBar"));
5757
}
5858

5959
@Test
6060
public void testIncludePrefixOverridesExclude() {
6161
ClassNameFiltering classNameFiltering =
6262
new ClassNameFiltering(
63-
Collections.singleton("com.datadog.debugger"), Collections.singleton("com.datadog"));
63+
Collections.singleton("com.datadog.debugger"),
64+
Collections.singleton("com.datadog"),
65+
Collections.emptySet());
6466
assertFalse(classNameFiltering.isExcluded("com.datadog.debugger.FooBar"));
6567
}
6668

@@ -69,7 +71,8 @@ public void testIncludeSomeExcludeSome() {
6971
ClassNameFiltering classNameFiltering =
7072
new ClassNameFiltering(
7173
Stream.of("com.datadog.debugger", "org.junit").collect(Collectors.toSet()),
72-
Collections.singleton("com.datadog.debugger"));
74+
Collections.singleton("com.datadog.debugger"),
75+
Collections.emptySet());
7376
assertFalse(classNameFiltering.isExcluded("com.datadog.debugger.FooBar"));
7477
assertTrue(classNameFiltering.isExcluded("org.junit.FooBar"));
7578
}
@@ -82,14 +85,15 @@ public void testIncludeSomeExcludeSome() {
8285
"akka.Actor",
8386
"cats.Functor",
8487
"org.junit.jupiter.api.Test",
85-
"org.datadog.jmxfetch.FooBar"
88+
"org.datadog.jmxfetch.FooBar",
89+
"shaded.org.junit.Test"
8690
})
8791
public void testExcludeDefaults(String input) {
8892
Config config = mock(Config.class);
8993
when(config.getThirdPartyExcludes()).thenReturn(Collections.emptySet());
9094
when(config.getThirdPartyIncludes()).thenReturn(Collections.emptySet());
91-
ClassNameFiltering classNameFiltering =
92-
new ClassNameFiltering(ThirdPartyLibraries.INSTANCE.getThirdPartyLibraries(config));
95+
when(config.getThirdPartyShadingIdentifiers()).thenReturn(Collections.emptySet());
96+
ClassNameFiltering classNameFiltering = new ClassNameFiltering(config);
9397
assertTrue(classNameFiltering.isExcluded(input));
9498
}
9599

dd-trace-api/src/main/java/datadog/trace/api/config/DebuggerConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public final class DebuggerConfig {
6161
public static final String DISTRIBUTED_DEBUGGER_ENABLED = "distributed.debugger.enabled";
6262
public static final String THIRD_PARTY_INCLUDES = "third.party.includes";
6363
public static final String THIRD_PARTY_EXCLUDES = "third.party.excludes";
64+
public static final String THIRD_PARTY_SHADING_IDENTIFIERS = "third.party.shading.identifiers";
6465

6566
private DebuggerConfig() {}
6667
}

internal-api/src/main/java/datadog/trace/api/Config.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ public static String getHostName() {
430430

431431
private final Set<String> debuggerThirdPartyIncludes;
432432
private final Set<String> debuggerThirdPartyExcludes;
433+
private final Set<String> debuggerShadingIdentifiers;
433434

434435
private final boolean awsPropagationEnabled;
435436
private final boolean sqsPropagationEnabled;
@@ -1734,6 +1735,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment())
17341735

17351736
debuggerThirdPartyIncludes = tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_INCLUDES));
17361737
debuggerThirdPartyExcludes = tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_EXCLUDES));
1738+
debuggerShadingIdentifiers =
1739+
tryMakeImmutableSet(configProvider.getList(THIRD_PARTY_SHADING_IDENTIFIERS));
17371740

17381741
awsPropagationEnabled = isPropagationEnabled(true, "aws", "aws-sdk");
17391742
sqsPropagationEnabled = isPropagationEnabled(true, "sqs");
@@ -3299,6 +3302,10 @@ public Set<String> getThirdPartyExcludes() {
32993302
return debuggerThirdPartyExcludes;
33003303
}
33013304

3305+
public Set<String> getThirdPartyShadingIdentifiers() {
3306+
return debuggerShadingIdentifiers;
3307+
}
3308+
33023309
private String getFinalDebuggerBaseUrl() {
33033310
if (agentUrl.startsWith("unix:")) {
33043311
// provide placeholder agent URL, in practice we'll be tunnelling over UDS

0 commit comments

Comments
 (0)