Skip to content

Commit fd79d6d

Browse files
committed
full pattern support
1 parent d0a8b22 commit fd79d6d

9 files changed

Lines changed: 105 additions & 47 deletions

File tree

bugsnag/src/main/java/com/bugsnag/Bugsnag.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.util.concurrent.ThreadFactory;
2323
import java.util.concurrent.ThreadPoolExecutor;
2424
import java.util.concurrent.TimeUnit;
25+
import java.util.regex.Pattern;
2526

2627
public class Bugsnag implements Closeable {
2728
private static final Logger LOGGER = LoggerFactory.getLogger(Bugsnag.class);
@@ -241,10 +242,11 @@ public void setRedactedKeys(String... redactedKeys) {
241242

242243
/**
243244
* Set which exception classes should be ignored (not sent) by Bugsnag.
245+
* Uses Java regex patterns for matching exception class names.
244246
*
245-
* @param discardClasses a list of exception classes to ignore
247+
* @param discardClasses compiled regex patterns to match exception class names
246248
*/
247-
public void setDiscardClasses(String... discardClasses) {
249+
public void setDiscardClasses(Pattern... discardClasses) {
248250
config.setDiscardClasses(discardClasses);
249251
}
250252

bugsnag/src/main/java/com/bugsnag/BugsnagAppender.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,12 @@ private Bugsnag createBugsnag() {
262262
bugsnag.setRedactedKeys(redactedKeys.toArray(new String[0]));
263263
}
264264

265-
bugsnag.setDiscardClasses(discardClasses.toArray(new String[0]));
265+
Pattern[] discardPatterns = new Pattern[discardClasses.size()];
266+
int idx = 0;
267+
for (String pattern : discardClasses) {
268+
discardPatterns[idx++] = Pattern.compile(pattern);
269+
}
270+
bugsnag.setDiscardClasses(discardPatterns);
266271

267272
if (!enabledReleaseStages.isEmpty()) {
268273
bugsnag.setEnabledReleaseStages(enabledReleaseStages.toArray(new String[0]));
@@ -406,24 +411,34 @@ public void setIgnoredClass(String ignoredClass) {
406411
}
407412

408413
/**
409-
* @see Bugsnag#setDiscardClasses(String...)
414+
* @see Bugsnag#setDiscardClasses(Pattern...)
410415
*/
411416
public void setDiscardClass(String discardClass) {
412417
this.discardClasses.add(discardClass);
413418

414419
if (bugsnag != null) {
415-
bugsnag.setDiscardClasses(this.discardClasses.toArray(new String[0]));
420+
Pattern[] discardPatterns = new Pattern[this.discardClasses.size()];
421+
int idx = 0;
422+
for (String pattern : this.discardClasses) {
423+
discardPatterns[idx++] = Pattern.compile(pattern);
424+
}
425+
bugsnag.setDiscardClasses(discardPatterns);
416426
}
417427
}
418428

419429
/**
420-
* @see Bugsnag#setDiscardClasses(String...)
430+
* @see Bugsnag#setDiscardClasses(Pattern...)
421431
*/
422432
public void setDiscardClasses(String discardClasses) {
423433
this.discardClasses.addAll(split(discardClasses));
424434

425435
if (bugsnag != null) {
426-
bugsnag.setDiscardClasses(this.discardClasses.toArray(new String[0]));
436+
Pattern[] discardPatterns = new Pattern[this.discardClasses.size()];
437+
int idx = 0;
438+
for (String pattern : this.discardClasses) {
439+
discardPatterns[idx++] = Pattern.compile(pattern);
440+
}
441+
bugsnag.setDiscardClasses(discardPatterns);
427442
}
428443
}
429444

bugsnag/src/main/java/com/bugsnag/Configuration.java

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -257,28 +257,47 @@ public void setRedactedKeys(String[] redactedKeys) {
257257
this.redactedKeys = redactedKeys;
258258
}
259259

260-
public String[] getDiscardClasses() {
261-
return discardClassStringPatterns.toArray(new String[0]);
260+
public Pattern[] getDiscardClasses() {
261+
return discardClassRegexPatterns.toArray(new Pattern[0]);
262262
}
263263

264264
/**
265265
* Set which exception classes should be ignored (not sent) by Bugsnag.
266-
* Supports Java regex patterns for matching exception class names.
267-
* For exact matches, use the fully qualified class name without regex metacharacters.
268-
* For pattern matching, use standard Java regex syntax (e.g., "java\\.io\\..*" to match all java.io exceptions).
266+
* Uses Java regex patterns for matching exception class names.
269267
*
270-
* @param discardClasses a list of exception class name patterns (regex) to ignore
268+
* @param discardClasses a list of compiled regex patterns to match exception class names
271269
*/
272-
public void setDiscardClasses(String[] discardClasses) {
270+
public void setDiscardClasses(Pattern[] discardClasses) {
273271
this.discardClassRegexPatterns.clear();
274272
this.discardClassStringPatterns.clear();
275273
if (discardClasses != null) {
276-
for (String pattern : discardClasses) {
277-
if (pattern != null && !pattern.isEmpty()) {
274+
for (Pattern pattern : discardClasses) {
275+
if (pattern != null) {
276+
// Store pattern
277+
this.discardClassRegexPatterns.add(pattern);
278+
// Store string representation for serialization
279+
this.discardClassStringPatterns.add(pattern.pattern());
280+
}
281+
}
282+
}
283+
}
284+
285+
/**
286+
* Set which exception classes should be ignored (not sent) by Bugsnag.
287+
* Compiles the provided strings as Java regex patterns.
288+
*
289+
* @param discardClasses a list of regex pattern strings to match exception class names
290+
*/
291+
public void setDiscardClassesFromStrings(String[] discardClasses) {
292+
this.discardClassRegexPatterns.clear();
293+
this.discardClassStringPatterns.clear();
294+
if (discardClasses != null) {
295+
for (String patternStr : discardClasses) {
296+
if (patternStr != null && !patternStr.isEmpty()) {
278297
// Store original pattern string
279-
this.discardClassStringPatterns.add(pattern);
298+
this.discardClassStringPatterns.add(patternStr);
280299
// Compile as regex pattern
281-
this.discardClassRegexPatterns.add(Pattern.compile(pattern));
300+
this.discardClassRegexPatterns.add(Pattern.compile(patternStr));
282301
}
283302
}
284303
}

bugsnag/src/test/java/com/bugsnag/AppenderTest.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.Arrays;
2121
import java.util.List;
2222
import java.util.Map;
23+
import java.util.regex.Pattern;
2324

2425
/**
2526
* Test for the Bugsnag Appender
@@ -148,9 +149,19 @@ public void testBugsnagConfig() {
148149
assertTrue(redactedKeys.contains("credit_card_number"));
149150

150151
assertEquals(2, config.getDiscardClasses().length);
151-
ArrayList<String> discardClasses = new ArrayList<String>(Arrays.asList(config.getDiscardClasses()));
152-
assertTrue(discardClasses.contains("com.example.Custom"));
153-
assertTrue(discardClasses.contains("java.io.IOException"));
152+
Pattern[] discardPatterns = config.getDiscardClasses();
153+
boolean hasCustom = false;
154+
boolean hasIoException = false;
155+
for (Pattern pattern : discardPatterns) {
156+
if (pattern.pattern().equals("com.example.Custom")) {
157+
hasCustom = true;
158+
}
159+
if (pattern.pattern().equals("java.io.IOException")) {
160+
hasIoException = true;
161+
}
162+
}
163+
assertTrue(hasCustom);
164+
assertTrue(hasIoException);
154165

155166
assertEquals(2, config.getEnabledReleaseStages().size());
156167
assertTrue(config.getEnabledReleaseStages().contains("development"));

bugsnag/src/test/java/com/bugsnag/BugsnagTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ public void testIgnoreClasses() {
6262
assertTrue(bugsnag.notify(new RuntimeException()));
6363
assertTrue(bugsnag.notify(new TestException()));
6464

65-
// Ignore just RuntimeException (escape dots for regex)
66-
bugsnag.setDiscardClasses(Pattern.quote(RuntimeException.class.getName()));
65+
// Ignore just RuntimeException (compile pattern for exact match)
66+
bugsnag.setDiscardClasses(Pattern.compile(Pattern.quote(RuntimeException.class.getName())));
6767
assertFalse(bugsnag.notify(new RuntimeException()));
6868
assertTrue(bugsnag.notify(new TestException()));
6969

70-
// Ignore both (escape special regex characters)
70+
// Ignore both (compile patterns for exact matches)
7171
bugsnag.setDiscardClasses(
72-
Pattern.quote(RuntimeException.class.getName()),
73-
Pattern.quote(TestException.class.getName())
72+
Pattern.compile(Pattern.quote(RuntimeException.class.getName())),
73+
Pattern.compile(Pattern.quote(TestException.class.getName()))
7474
);
7575
assertFalse(bugsnag.notify(new RuntimeException()));
7676
assertFalse(bugsnag.notify(new TestException()));

bugsnag/src/test/java/com/bugsnag/ConfigurationDiscardClassesTest.java

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import org.junit.Before;
88
import org.junit.Test;
99

10+
import java.util.regex.Pattern;
11+
1012
/**
1113
* Test for Configuration.shouldIgnoreClass with regex pattern matching
1214
*/
@@ -21,15 +23,15 @@ public void setUp() {
2123

2224
@Test
2325
public void testExactMatch() {
24-
config.setDiscardClasses(new String[] {"com.example.CustomException"});
26+
config.setDiscardClasses(new Pattern[] {Pattern.compile("com.example.CustomException")});
2527

2628
assertTrue(config.shouldIgnoreClass("com.example.CustomException"));
2729
assertFalse(config.shouldIgnoreClass("com.example.OtherException"));
2830
}
2931

3032
@Test
3133
public void testWildcardMatch() {
32-
config.setDiscardClasses(new String[] {"com\\.example\\..*"});
34+
config.setDiscardClasses(new Pattern[] {Pattern.compile("com\\.example\\..*")});
3335

3436
assertTrue(config.shouldIgnoreClass("com.example.CustomException"));
3537
assertTrue(config.shouldIgnoreClass("com.example.OtherException"));
@@ -39,7 +41,7 @@ public void testWildcardMatch() {
3941

4042
@Test
4143
public void testMultipleWildcards() {
42-
config.setDiscardClasses(new String[] {"com\\..*\\.Exception"});
44+
config.setDiscardClasses(new Pattern[] {Pattern.compile("com\\..*\\.Exception")});
4345

4446
assertTrue(config.shouldIgnoreClass("com.example.Exception"));
4547
assertTrue(config.shouldIgnoreClass("com.other.Exception"));
@@ -48,7 +50,7 @@ public void testMultipleWildcards() {
4850

4951
@Test
5052
public void testQuestionMarkWildcard() {
51-
config.setDiscardClasses(new String[] {"com\\.example\\.Exception."});
53+
config.setDiscardClasses(new Pattern[] {Pattern.compile("com\\.example\\.Exception.")});
5254

5355
assertTrue(config.shouldIgnoreClass("com.example.Exception1"));
5456
assertTrue(config.shouldIgnoreClass("com.example.ExceptionX"));
@@ -58,10 +60,10 @@ public void testQuestionMarkWildcard() {
5860

5961
@Test
6062
public void testMultiplePatterns() {
61-
config.setDiscardClasses(new String[] {
62-
"java\\.io\\..*",
63-
"com\\.example\\.CustomException",
64-
"org\\..*\\.SpecialException"
63+
config.setDiscardClasses(new Pattern[] {
64+
Pattern.compile("java\\.io\\..*"),
65+
Pattern.compile("com\\.example\\.CustomException"),
66+
Pattern.compile("org\\..*\\.SpecialException")
6567
});
6668

6769
assertTrue(config.shouldIgnoreClass("java.io.IOException"));
@@ -74,20 +76,23 @@ public void testMultiplePatterns() {
7476

7577
@Test
7678
public void testGetDiscardClassesReturnsOriginalPatterns() {
77-
String[] patterns = new String[] {"com\\.example\\..*", "java\\.io\\.IOException"};
79+
Pattern[] patterns = new Pattern[] {
80+
Pattern.compile("com\\.example\\..*"),
81+
Pattern.compile("java\\.io\\.IOException")
82+
};
7883
config.setDiscardClasses(patterns);
7984

80-
String[] retrieved = config.getDiscardClasses();
85+
Pattern[] retrieved = config.getDiscardClasses();
8186
assertEquals(2, retrieved.length);
8287

83-
// Check that patterns are returned (not regex)
88+
// Check that patterns are returned
8489
boolean hasWildcard = false;
8590
boolean hasExact = false;
86-
for (String pattern : retrieved) {
87-
if (pattern.equals("com\\.example\\..*")) {
91+
for (Pattern pattern : retrieved) {
92+
if (pattern.pattern().equals("com\\.example\\..*")) {
8893
hasWildcard = true;
8994
}
90-
if (pattern.equals("java\\.io\\.IOException")) {
95+
if (pattern.pattern().equals("java\\.io\\.IOException")) {
9196
hasExact = true;
9297
}
9398
}
@@ -97,7 +102,7 @@ public void testGetDiscardClassesReturnsOriginalPatterns() {
97102

98103
@Test
99104
public void testEmptyAndNullPatterns() {
100-
config.setDiscardClasses(new String[] {});
105+
config.setDiscardClasses(new Pattern[] {});
101106
assertFalse(config.shouldIgnoreClass("com.example.Exception"));
102107

103108
config.setDiscardClasses(null);
@@ -107,7 +112,7 @@ public void testEmptyAndNullPatterns() {
107112
@Test
108113
public void testSpecialCharactersAreEscaped() {
109114
// In regex, $ is a special character (end of line), so it needs to be escaped
110-
config.setDiscardClasses(new String[] {"com\\.example\\.Exception\\$Inner"});
115+
config.setDiscardClasses(new Pattern[] {Pattern.compile("com\\.example\\.Exception\\$Inner")});
111116

112117
assertTrue(config.shouldIgnoreClass("com.example.Exception$Inner"));
113118
assertFalse(config.shouldIgnoreClass("com.example.ExceptionXInner"));

features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/IgnoredExceptionScenario.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.bugsnag.Bugsnag;
44

5+
import java.util.regex.Pattern;
6+
57
/**
68
* Attempts to send an ignored handled exception to Bugsnag, which should not result
79
* in any operation.
@@ -15,7 +17,7 @@ public IgnoredExceptionScenario(Bugsnag bugsnag) {
1517
@Override
1618
public void run() {
1719

18-
bugsnag.setDiscardClasses("java.lang.RuntimeException");
20+
bugsnag.setDiscardClasses(Pattern.compile("java.lang.RuntimeException"));
1921

2022
bugsnag.notify(new RuntimeException("Should never appear"));
2123
}

features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/IgnoredExceptionWildcardScenario.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.bugsnag.Bugsnag;
44

5+
import java.util.regex.Pattern;
6+
57
/**
68
* Attempts to send ignored handled exceptions using regex patterns to Bugsnag,
79
* which should not result in any operation.
@@ -15,7 +17,7 @@ public IgnoredExceptionWildcardScenario(Bugsnag bugsnag) {
1517
@Override
1618
public void run() {
1719
// Use regex pattern to ignore all java.lang exceptions
18-
bugsnag.setDiscardClasses("java\\.lang\\..*");
20+
bugsnag.setDiscardClasses(Pattern.compile("java\\.lang\\..*"));
1921

2022
// These should all be ignored due to the regex pattern
2123
bugsnag.notify(new RuntimeException("Should never appear"));

features/fixtures/scenarios/src/main/java/com/bugsnag/mazerunner/scenarios/MultipleWildcardPatternsScenario.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.bugsnag.Bugsnag;
44

5+
import java.util.regex.Pattern;
6+
57
/**
68
* Tests multiple regex patterns working together.
79
*/
@@ -15,9 +17,9 @@ public MultipleWildcardPatternsScenario(Bugsnag bugsnag) {
1517
public void run() {
1618
// Set multiple regex patterns: matching specific packages and classes
1719
bugsnag.setDiscardClasses(
18-
"java\\.io\\..*", // All java.io exceptions
19-
"java\\.lang\\.IllegalStateException", // Exact match
20-
"java\\.lang\\.Illegal.*" // All IllegalXException classes
20+
Pattern.compile("java\\.io\\..*"), // All java.io exceptions
21+
Pattern.compile("java\\.lang\\.IllegalStateException"), // Exact match
22+
Pattern.compile("java\\.lang\\.Illegal.*") // All IllegalXException classes
2123
);
2224

2325
// These should all be ignored

0 commit comments

Comments
 (0)