Skip to content

Commit 2e1e4ae

Browse files
martinhaintzmar-haibuenaflor
authored
feat: add ignoreTransactions and ignoreErrors` #1391 (#2207)
* Add ignoreTransactions and ignoreErrors #1391 * chore: add changelog entry * move methods from sentry_options to sentry_client and change to private * change discard reason to ignored Co-authored-by: Giancarlo Buenaflor <[email protected]> * change iterable to list * add event recorder to ignoredTransactions * add tests for ignoreTransactions * set ignoreErrors list to empty list a default Co-authored-by: Giancarlo Buenaflor <[email protected]> * change variables to final for ignoreTransaction Co-authored-by: Giancarlo Buenaflor <[email protected]> * change var to final for ignoreErrors and adapt test * Update CHANGELOG.md Co-authored-by: Giancarlo Buenaflor <[email protected]> * Add example for ignoreTransactions and ignoreErrors to changelog * fix: check for empty ignoreError and ignoreTransaction before handling regex * moved ignoreTransactions and ignoreErrors back to unreleased area in CHANGELOG.md * refactored implementation of ignoreErrors and ignoreTransactions and improved test cases * removed unnecessary backslash from tests --------- Co-authored-by: Martin <> Co-authored-by: Martin <[email protected]> Co-authored-by: Giancarlo Buenaflor <[email protected]>
1 parent 7ec9238 commit 2e1e4ae

File tree

4 files changed

+190
-0
lines changed

4 files changed

+190
-0
lines changed

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
### Features
66

77
- Add support for span level measurements. ([#2214](https://github.com/getsentry/sentry-dart/pull/2214))
8+
- Add `ignoreTransactions` and `ignoreErrors` to options ([#2207](https://github.com/getsentry/sentry-dart/pull/2207))
9+
```dart
10+
await SentryFlutter.init(
11+
(options) {
12+
options.dsn = 'https://[email protected]/0';
13+
options.ignoreErrors = ["my-error", "^error-.*\$"];
14+
options.ignoreTransactions = ["my-transaction", "^transaction-.*\$"];
15+
...
16+
},
17+
appRunner: () => runApp(MyApp()),
18+
);
19+
```
820

921
## 8.6.0
1022

dart/lib/src/sentry_client.dart

+46
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@ class SentryClient {
8484
dynamic stackTrace,
8585
Hint? hint,
8686
}) async {
87+
if (_isIgnoredError(event)) {
88+
_options.logger(
89+
SentryLevel.debug,
90+
'Error was ignored as specified in the ignoredErrors options.',
91+
);
92+
_options.recorder
93+
.recordLostEvent(DiscardReason.ignored, _getCategory(event));
94+
return _emptySentryId;
95+
}
96+
8797
if (_options.containsIgnoredExceptionForType(event.throwable)) {
8898
_options.logger(
8999
SentryLevel.debug,
@@ -180,6 +190,15 @@ class SentryClient {
180190
return id ?? SentryId.empty();
181191
}
182192

193+
bool _isIgnoredError(SentryEvent event) {
194+
if (event.message == null || _options.ignoreErrors.isEmpty) {
195+
return false;
196+
}
197+
198+
var message = event.message!.formatted;
199+
return _isMatchingRegexPattern(message, _options.ignoreErrors);
200+
}
201+
183202
SentryEvent _prepareEvent(SentryEvent event, {dynamic stackTrace}) {
184203
event = event.copyWith(
185204
serverName: event.serverName ?? _options.serverName,
@@ -351,6 +370,17 @@ class SentryClient {
351370
return _emptySentryId;
352371
}
353372

373+
if (_isIgnoredTransaction(preparedTransaction)) {
374+
_options.logger(
375+
SentryLevel.debug,
376+
'Transaction was ignored as specified in the ignoredTransactions options.',
377+
);
378+
379+
_options.recorder.recordLostEvent(
380+
DiscardReason.ignored, _getCategory(preparedTransaction));
381+
return _emptySentryId;
382+
}
383+
354384
preparedTransaction =
355385
await _runBeforeSend(preparedTransaction, hint) as SentryTransaction?;
356386

@@ -379,6 +409,15 @@ class SentryClient {
379409
return id ?? SentryId.empty();
380410
}
381411

412+
bool _isIgnoredTransaction(SentryTransaction transaction) {
413+
if (_options.ignoreTransactions.isEmpty) {
414+
return false;
415+
}
416+
417+
var name = transaction.tracer.name;
418+
return _isMatchingRegexPattern(name, _options.ignoreTransactions);
419+
}
420+
382421
/// Reports the [envelope] to Sentry.io.
383422
Future<SentryId?> captureEnvelope(SentryEnvelope envelope) {
384423
return _attachClientReportsAndSend(envelope);
@@ -554,4 +593,11 @@ class SentryClient {
554593
SentryId.empty(),
555594
);
556595
}
596+
597+
bool _isMatchingRegexPattern(String value, List<String> regexPattern,
598+
{bool caseSensitive = false}) {
599+
final combinedRegexPattern = regexPattern.join('|');
600+
final regExp = RegExp(combinedRegexPattern, caseSensitive: caseSensitive);
601+
return regExp.hasMatch(value);
602+
}
557603
}

dart/lib/src/sentry_options.dart

+8
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,14 @@ class SentryOptions {
184184
/// sent. Events are picked randomly. Default is null (disabled)
185185
double? sampleRate;
186186

187+
/// The ignoreErrors tells the SDK which errors should be not sent to the sentry server.
188+
/// If an null or an empty list is used, the SDK will send all transactions.
189+
List<String> ignoreErrors = [];
190+
191+
/// The ignoreTransactions tells the SDK which transactions should be not sent to the sentry server.
192+
/// If null or an empty list is used, the SDK will send all transactions.
193+
List<String> ignoreTransactions = [];
194+
187195
final List<String> _inAppExcludes = [];
188196

189197
/// A list of string prefixes of packages names that do not belong to the app, but rather third-party

dart/test/sentry_client_test.dart

+124
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,130 @@ void main() {
10331033
});
10341034
});
10351035

1036+
group('SentryClient ignored errors', () {
1037+
late Fixture fixture;
1038+
1039+
setUp(() {
1040+
fixture = Fixture();
1041+
fixture.options.ignoreErrors = ["my-error", "^error-.*\$"];
1042+
});
1043+
1044+
test('drop event if error message fully matches ignoreErrors value',
1045+
() async {
1046+
final event = SentryEvent(message: SentryMessage("my-error"));
1047+
1048+
final client = fixture.getSut();
1049+
await client.captureEvent(event);
1050+
1051+
expect((fixture.transport).called(0), true);
1052+
});
1053+
1054+
test('drop event if error message partially matches ignoreErrors value',
1055+
() async {
1056+
final event = SentryEvent(message: SentryMessage("this is my-error-foo"));
1057+
1058+
final client = fixture.getSut();
1059+
await client.captureEvent(event);
1060+
1061+
expect((fixture.transport).called(0), true);
1062+
});
1063+
1064+
test(
1065+
'drop event if error message partially matches ignoreErrors regex value',
1066+
() async {
1067+
final event = SentryEvent(message: SentryMessage("error-test message"));
1068+
1069+
final client = fixture.getSut();
1070+
await client.captureEvent(event);
1071+
1072+
expect((fixture.transport).called(0), true);
1073+
});
1074+
1075+
test('send event if error message does not match ignoreErrors value',
1076+
() async {
1077+
final event = SentryEvent(message: SentryMessage("warning"));
1078+
1079+
final client = fixture.getSut();
1080+
await client.captureEvent(event);
1081+
1082+
expect((fixture.transport).called(1), true);
1083+
});
1084+
1085+
test('send event if no values are set for ignoreErrors', () async {
1086+
fixture.options.ignoreErrors = [];
1087+
final event = SentryEvent(message: SentryMessage("this is a test event"));
1088+
1089+
final client = fixture.getSut();
1090+
await client.captureEvent(event);
1091+
1092+
expect((fixture.transport).called(1), true);
1093+
});
1094+
});
1095+
1096+
group('SentryClient ignored transactions', () {
1097+
late Fixture fixture;
1098+
1099+
setUp(() {
1100+
fixture = Fixture();
1101+
fixture.options.ignoreTransactions = [
1102+
"my-transaction",
1103+
"^transaction-.*\$"
1104+
];
1105+
});
1106+
1107+
test('drop transaction if name fully matches ignoreTransaction value',
1108+
() async {
1109+
final client = fixture.getSut();
1110+
final fakeTransaction = fixture.fakeTransaction();
1111+
fakeTransaction.tracer.name = "my-transaction";
1112+
await client.captureTransaction(fakeTransaction);
1113+
1114+
expect((fixture.transport).called(0), true);
1115+
});
1116+
1117+
test('drop transaction if name partially matches ignoreTransaction value',
1118+
() async {
1119+
final client = fixture.getSut();
1120+
final fakeTransaction = fixture.fakeTransaction();
1121+
fakeTransaction.tracer.name = "this is a transaction-test";
1122+
await client.captureTransaction(fakeTransaction);
1123+
1124+
expect((fixture.transport).called(0), true);
1125+
});
1126+
1127+
test(
1128+
'drop transaction if name partially matches ignoreTransaction regex value',
1129+
() async {
1130+
final client = fixture.getSut();
1131+
final fakeTransaction = fixture.fakeTransaction();
1132+
fakeTransaction.tracer.name = "transaction-test message";
1133+
await client.captureTransaction(fakeTransaction);
1134+
1135+
expect((fixture.transport).called(0), true);
1136+
});
1137+
1138+
test('send transaction if name does not match ignoreTransaction value',
1139+
() async {
1140+
final client = fixture.getSut();
1141+
final fakeTransaction = fixture.fakeTransaction();
1142+
fakeTransaction.tracer.name = "capture";
1143+
await client.captureTransaction(fakeTransaction);
1144+
1145+
expect((fixture.transport).called(1), true);
1146+
});
1147+
1148+
test('send transaction if no values are set for ignoreTransaction',
1149+
() async {
1150+
fixture.options.ignoreTransactions = [];
1151+
final client = fixture.getSut();
1152+
final fakeTransaction = fixture.fakeTransaction();
1153+
fakeTransaction.tracer.name = "this is a test transaction";
1154+
await client.captureTransaction(fakeTransaction);
1155+
1156+
expect((fixture.transport).called(1), true);
1157+
});
1158+
});
1159+
10361160
group('SentryClient ignored exceptions', () {
10371161
late Fixture fixture;
10381162

0 commit comments

Comments
 (0)