Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
e3166cb
add android (tested) and ios (untested)
lucas-zimerman Jun 24, 2025
981a304
do not use integration/ refactor to also accept strings and regex
lucas-zimerman Jun 24, 2025
04b7811
simplify logic
lucas-zimerman Jun 24, 2025
bb17019
use JS pattern for strings on native layers (Android OK/ iOS WIP). Sp…
lucas-zimerman Jun 25, 2025
71751d8
apply changes to iOS
lucas-zimerman Jun 25, 2025
cb7f77b
lint fix
lucas-zimerman Jun 25, 2025
f2d3913
fix kotlin format
lucas-zimerman Jun 25, 2025
f7c17b4
Merge branch 'v7' into lz/v7/ignore-errors
lucas-zimerman Jun 25, 2025
0dae08c
update changelog
lucas-zimerman Jun 25, 2025
713a3b4
fix android tests
lucas-zimerman Jun 26, 2025
bb91908
update changelog
lucas-zimerman Jun 26, 2025
a9ee127
add space
lucas-zimerman Jun 26, 2025
9eb02af
add reference to regex
lucas-zimerman Jun 26, 2025
8ae5aea
fix kotlin tests / add js tests
lucas-zimerman Jun 26, 2025
42a68cd
fix ios tests and fix some logic issues
lucas-zimerman Jun 26, 2025
ac4d7ea
manual lint:
lucas-zimerman Jun 26, 2025
7bad6cb
nit
lucas-zimerman Jun 26, 2025
e678ad7
more manual nits
lucas-zimerman Jun 26, 2025
0bf35ea
more nits
lucas-zimerman Jun 26, 2025
f187794
lint
lucas-zimerman Jun 26, 2025
4c86441
final nit?
lucas-zimerman Jun 26, 2025
71a09af
Update CHANGELOG.md
lucas-zimerman Jun 27, 2025
38f9fcd
Apply suggestions from code review
lucas-zimerman Jun 27, 2025
49c9caf
will it fix lint?
lucas-zimerman Jun 27, 2025
c2f4049
rollback delted code
lucas-zimerman Jun 27, 2025
6d664ba
lint fix?
lucas-zimerman Jun 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@
> make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first.
<!-- prettier-ignore-end -->

## Unreleased

### Fixes

- ignoreError now filters Native errors ([#4948](https://github.com/getsentry/sentry-react-native/pull/4948))

You can use strings to filter errors or RegEx for filtering with a pattern.

example:

```typescript
ignoreErrors: [
'1234', // Will filter any error message that contains 1234.
'.*1234', // Will not filter as regex, instead will filter messages that contains '.*1234"
/.*1234/, // Regex will filter any error message that ends with 1234
/.*1234.*/ // Regex will filter any error message that contains 1234.
]
```

## 7.0.0-beta.1

### Upgrading from 6.x to 7.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,91 @@ class RNSentryModuleImplTest {

assertEquals(breadcrumb, result)
}

@Test
fun `trySetIgnoreErrors sets only regex patterns`() {
val options = SentryAndroidOptions()
val rnOptions =
JavaOnlyMap.of(
"ignoreErrorsRegex",
com.facebook.react.bridge.JavaOnlyArray
.of("^Foo.*", "Bar$"),
)
module.trySetIgnoreErrors(options, rnOptions)
assertEquals(listOf("^Foo.*", "Bar$"), options.ignoredErrors!!.map { it.filterString })
}

@Test
fun `trySetIgnoreErrors sets only string patterns`() {
val options = SentryAndroidOptions()
val rnOptions =
JavaOnlyMap.of(
"ignoreErrorsStr",
com.facebook.react.bridge.JavaOnlyArray
.of("ExactError", "AnotherError"),
)
module.trySetIgnoreErrors(options, rnOptions)
assertEquals(listOf(".*\\QExactError\\E.*", ".*\\QAnotherError\\E.*"), options.ignoredErrors!!.map { it.filterString })
}

@Test
fun `trySetIgnoreErrors sets both regex and string patterns`() {
val options = SentryAndroidOptions()
val rnOptions =
JavaOnlyMap.of(
"ignoreErrorsRegex",
com.facebook.react.bridge.JavaOnlyArray
.of("^Foo.*"),
"ignoreErrorsStr",
com.facebook.react.bridge.JavaOnlyArray
.of("ExactError"),
)
module.trySetIgnoreErrors(options, rnOptions)
assertEquals(listOf("^Foo.*", ".*\\QExactError\\E.*"), options.ignoredErrors!!.map { it.filterString })
}

@Test
fun `trySetIgnoreErrors sets nothing if neither is present`() {
val options = SentryAndroidOptions()
val rnOptions = JavaOnlyMap.of()
module.trySetIgnoreErrors(options, rnOptions)
assertNull(options.ignoredErrors)
}

@Test
fun `trySetIgnoreErrors with string containing regex special characters should match literally if Pattern_quote is used`() {
val options = SentryAndroidOptions()
val special = "I like chocolate (and tomato)."
val rnOptions =
JavaOnlyMap.of(
"ignoreErrorsStr",
com.facebook.react.bridge.JavaOnlyArray
.of(special),
)
module.trySetIgnoreErrors(options, rnOptions)

assertEquals(listOf(".*\\QI like chocolate (and tomato).\\E.*"), options.ignoredErrors!!.map { it.filterString })

val regex = Regex(options.ignoredErrors!![0].filterString)
assertTrue(regex.matches("I like chocolate (and tomato)."))
assertTrue(regex.matches(" I like chocolate (and tomato). "))
assertTrue(regex.matches("I like chocolate (and tomato). And vanilla."))
}

@Test
fun `trySetIgnoreErrors with string containing star should not match everything if Pattern_quote is used`() {
val options = SentryAndroidOptions()
val special = "Error*WithStar"
val rnOptions =
JavaOnlyMap.of(
"ignoreErrorsStr",
com.facebook.react.bridge.JavaOnlyArray
.of(special),
)
module.trySetIgnoreErrors(options, rnOptions)
assertEquals(listOf(".*\\QError*WithStar\\E.*"), options.ignoredErrors!!.map { it.filterString })

val regex = Regex(options.ignoredErrors!![0].filterString)
assertTrue(regex.matches("Error*WithStar"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -500,4 +500,119 @@ - (void)testFetchNativeStackFramesByInstructionsOnDeviceSymbolication
XCTAssertTrue([actual isEqualToDictionary:expected]);
}

- (void)testIgnoreErrorsDropsMatchingExceptionValue
{
RNSentry *rnSentry = [[RNSentry alloc] init];
NSError *error = nil;
NSDictionary *mockedOptions = @{
@"dsn" : @"https://abc@def.ingest.sentry.io/1234567",
@"ignoreErrorsRegex" : @[ @"IgnoreMe.*" ]
};
SentryOptions *options = [rnSentry createOptionsWithDictionary:mockedOptions error:&error];
XCTAssertNotNil(options);
XCTAssertNil(error);
SentryEvent *event = [[SentryEvent alloc] init];
SentryException *exception = [SentryException alloc];
exception.value = @"IgnoreMe: This should be ignored";
event.exceptions = @[ exception ];
SentryEvent *result = options.beforeSend(event);
XCTAssertNil(result, @"Event with matching exception.value should be dropped");
}

- (void)testIgnoreErrorsDropsMatchingEventMessage
{
RNSentry *rnSentry = [[RNSentry alloc] init];
NSError *error = nil;
NSDictionary *mockedOptions = @{
@"dsn" : @"https://abc@def.ingest.sentry.io/1234567",
@"ignoreErrorsStr" : @[ @"DropThisError" ]
};
SentryOptions *options = [rnSentry createOptionsWithDictionary:mockedOptions error:&error];
XCTAssertNotNil(options);
XCTAssertNil(error);
SentryEvent *event = [[SentryEvent alloc] init];
SentryMessage *msg = [SentryMessage alloc];
msg.message = @"DropThisError: should be dropped";
event.message = msg;
SentryEvent *result = options.beforeSend(event);
XCTAssertNil(result, @"Event with matching event.message.formatted should be dropped");
}

- (void)testIgnoreErrorsDoesNotDropNonMatchingEvent
{
RNSentry *rnSentry = [[RNSentry alloc] init];
NSError *error = nil;
NSDictionary *mockedOptions = @{
@"dsn" : @"https://abc@def.ingest.sentry.io/1234567",
@"ignoreErrorsRegex" : @[ @"IgnoreMe.*" ]
};
SentryOptions *options = [rnSentry createOptionsWithDictionary:mockedOptions error:&error];
XCTAssertNotNil(options);
XCTAssertNil(error);
SentryEvent *event = [[SentryEvent alloc] init];
SentryException *exception = [SentryException alloc];
exception.value = @"SomeOtherError: should not be ignored";
event.exceptions = @[ exception ];
SentryMessage *msg = [SentryMessage alloc];
msg.message = @"SomeOtherMessage";
event.message = msg;
SentryEvent *result = options.beforeSend(event);
XCTAssertNotNil(result, @"Event with non-matching error should not be dropped");
}

- (void)testIgnoreErrorsDropsMatchingExactString
{
RNSentry *rnSentry = [[RNSentry alloc] init];
NSError *error = nil;
NSDictionary *mockedOptions = @{
@"dsn" : @"https://abc@def.ingest.sentry.io/1234567",
@"ignoreErrorsStr" : @[ @"ExactError" ]
};
SentryOptions *options = [rnSentry createOptionsWithDictionary:mockedOptions error:&error];
XCTAssertNotNil(options);
XCTAssertNil(error);
SentryEvent *event = [[SentryEvent alloc] init];
SentryMessage *msg = [SentryMessage alloc];
msg.message = @"ExactError";
event.message = msg;
SentryEvent *result = options.beforeSend(event);
XCTAssertNil(result, @"Event with exactly matching string should be dropped");
}

- (void)testIgnoreErrorsRegexAndStringBothWork
{
RNSentry *rnSentry = [[RNSentry alloc] init];
NSError *error = nil;
NSDictionary *mockedOptions = @{
@"dsn" : @"https://abc@def.ingest.sentry.io/1234567",
@"ignoreErrorsStr" : @[ @"ExactError" ],
@"ignoreErrorsRegex" : @[ @"IgnoreMe.*" ],

};
SentryOptions *options = [rnSentry createOptionsWithDictionary:mockedOptions error:&error];
XCTAssertNotNil(options);
XCTAssertNil(error);
// Test regex match
SentryEvent *event1 = [[SentryEvent alloc] init];
SentryException *exception = [SentryException alloc];
exception.value = @"IgnoreMe: This should be ignored";
event1.exceptions = @[ exception ];
SentryEvent *result1 = options.beforeSend(event1);
XCTAssertNil(result1, @"Event with matching regex should be dropped");
// Test exact string match
SentryEvent *event2 = [[SentryEvent alloc] init];
SentryMessage *msg = [SentryMessage alloc];
msg.message = @"ExactError";
event2.message = msg;
SentryEvent *result2 = options.beforeSend(event2);
XCTAssertNil(result2, @"Event with exactly matching string should be dropped");
// Test non-matching
SentryEvent *event3 = [[SentryEvent alloc] init];
SentryMessage *msg3 = [SentryMessage alloc];
msg3.message = @"OtherError";
event3.message = msg3;
SentryEvent *result3 = options.beforeSend(event3);
XCTAssertNotNil(result3, @"Event with non-matching error should not be dropped");
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,15 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Pattern;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
Expand Down Expand Up @@ -320,6 +322,8 @@ protected void getSentryAndroidOptions(
// we want to ignore it on the native side to avoid sending it twice.
options.addIgnoredExceptionForType(JavascriptException.class);

trySetIgnoreErrors(options, rnOptions);

options.setBeforeSend(
(event, hint) -> {
setEventOriginTag(event);
Expand Down Expand Up @@ -1126,4 +1130,36 @@ private boolean isFrameMetricsAggregatorAvailable() {
}
return uri.getScheme() + "://" + uri.getHost();
}

@TestOnly
protected void trySetIgnoreErrors(SentryAndroidOptions options, ReadableMap rnOptions) {
ReadableArray regErrors = null;
ReadableArray strErrors = null;
if (rnOptions.hasKey("ignoreErrorsRegex")) {
regErrors = rnOptions.getArray("ignoreErrorsRegex");
}
if (rnOptions.hasKey("ignoreErrorsStr")) {
strErrors = rnOptions.getArray("ignoreErrorsStr");
}
if (regErrors == null && strErrors == null) {
return;
}

int regSize = regErrors != null ? regErrors.size() : 0;
int strSize = strErrors != null ? strErrors.size() : 0;
List<String> list = new ArrayList<>(regSize + strSize);
if (regErrors != null) {
for (int i = 0; i < regErrors.size(); i++) {
list.add(regErrors.getString(i));
}
}
if (strErrors != null) {
// Use the same behaviour of JavaScript instead of Android when dealing with strings.
for (int i = 0; i < strErrors.size(); i++) {
String pattern = ".*" + Pattern.quote(strErrors.getString(i)) + ".*";
list.add(pattern);
}
}
options.setIgnoredErrors(list);
}
}
Loading
Loading