Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support allowUrls, denyUrls #2227

Merged
merged 23 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
47beb08
moved regex matcher into regex utils
martinhaintz Aug 12, 2024
65c2868
add allowUrls, denyUrls for web
martinhaintz Aug 12, 2024
92f02c3
add changelog entry for allowUrls and denyUrls
martinhaintz Aug 13, 2024
11a06c5
add conditional import for non web platforms
martinhaintz Aug 13, 2024
934c9d0
fix multiplatform build
martinhaintz Aug 13, 2024
24c48e9
fix wording in sentry options
martinhaintz Aug 13, 2024
e510129
Update dart/lib/src/utils/regex_utils.dart
martinhaintz Aug 13, 2024
5d62144
Update dart/lib/src/sentry_options.dart
martinhaintz Aug 13, 2024
f623e07
Update dart/lib/src/sentry_options.dart
martinhaintz Aug 13, 2024
40cadc9
add tests for isMatchingRegexPattern
martinhaintz Aug 13, 2024
2812a96
simplified allowUrls and denyUrls handling
martinhaintz Aug 13, 2024
c0ffc67
moved allowUrls and denyUrls from dart to flutter
martinhaintz Aug 13, 2024
5598f4c
Merge branch 'main' into feat/support-allow-urls-deny-urls
martinhaintz Aug 13, 2024
8523a6d
add event processor for html
martinhaintz Aug 13, 2024
a30a862
rephrased documentation and split up tests for web and mobile platform.
martinhaintz Aug 14, 2024
1ec7235
Merge branch 'main' into feat/support-allow-urls-deny-urls
martinhaintz Aug 14, 2024
160ddcc
add expected error
martinhaintz Aug 14, 2024
dc06ba9
Update scripts/publish_validation/bin/publish_validation.dart
martinhaintz Aug 19, 2024
e38e625
Update flutter/lib/src/event_processor/url_filter/html_url_filter_eve…
martinhaintz Aug 19, 2024
5e7ccc1
Update flutter/lib/src/event_processor/url_filter/web_url_filter_even…
martinhaintz Aug 19, 2024
a4c0d59
Merge branch 'main' into feat/support-allow-urls-deny-urls
martinhaintz Aug 19, 2024
102f0e5
modified code to go through stacktrace frames
martinhaintz Sep 2, 2024
e5a3315
Merge branch 'main' into feat/support-allow-urls-deny-urls
martinhaintz Sep 2, 2024
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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@

### Features

- Support allowUrls and denyUrls for Flutter Web ([#2227](https://github.com/getsentry/sentry-dart/pull/2227))

```dart
await SentryFlutter.init(
(options) {
...
options.allowUrls = ["^https://sentry.com.*\$", "my-custom-domain"];
options.denyUrls = ["^.*ends-with-this\$", "denied-url"];
},
appRunner: () => runApp(MyApp()),
);
```

- Session replay Alpha for Android and iOS ([#2208](https://github.com/getsentry/sentry-dart/pull/2208)).

To try out replay, you can set following options (access is limited to early access orgs on Sentry. If you're interested, [sign up for the waitlist](https://sentry.io/lp/mobile-replay-beta/)):
Expand Down Expand Up @@ -31,6 +44,7 @@

- Add `SentryFlutter.nativeCrash()` using MethodChannels for Android and iOS ([#2239](https://github.com/getsentry/sentry-dart/pull/2239))
- This can be used to test if native crash reporting works

- Add `ignoreRoutes` parameter to `SentryNavigatorObserver`. ([#2218](https://github.com/getsentry/sentry-dart/pull/2218))
- This will ignore the Routes and prevent the Route from being pushed to the Sentry server.
- Ignored routes will also create no TTID and TTFD spans.
Expand Down
12 changes: 3 additions & 9 deletions dart/lib/src/sentry_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import 'transport/rate_limiter.dart';
import 'transport/spotlight_http_transport.dart';
import 'transport/task_queue.dart';
import 'utils/isolate_utils.dart';
import 'utils/regex_utils.dart';
import 'utils/stacktrace_utils.dart';
import 'version.dart';

Expand Down Expand Up @@ -196,7 +197,7 @@ class SentryClient {
}

var message = event.message!.formatted;
return _isMatchingRegexPattern(message, _options.ignoreErrors);
return isMatchingRegexPattern(message, _options.ignoreErrors);
}

SentryEvent _prepareEvent(SentryEvent event, {dynamic stackTrace}) {
Expand Down Expand Up @@ -415,7 +416,7 @@ class SentryClient {
}

var name = transaction.tracer.name;
return _isMatchingRegexPattern(name, _options.ignoreTransactions);
return isMatchingRegexPattern(name, _options.ignoreTransactions);
}

/// Reports the [envelope] to Sentry.io.
Expand Down Expand Up @@ -593,11 +594,4 @@ class SentryClient {
SentryId.empty(),
);
}

bool _isMatchingRegexPattern(String value, List<String> regexPattern,
{bool caseSensitive = false}) {
final combinedRegexPattern = regexPattern.join('|');
final regExp = RegExp(combinedRegexPattern, caseSensitive: caseSensitive);
return regExp.hasMatch(value);
}
}
2 changes: 2 additions & 0 deletions dart/lib/src/sentry_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,12 @@ class SentryOptions {

/// The ignoreErrors tells the SDK which errors should be not sent to the sentry server.
/// If an null or an empty list is used, the SDK will send all transactions.
/// To use regex add the `^` and the `$` to the string.
List<String> ignoreErrors = [];

/// The ignoreTransactions tells the SDK which transactions should be not sent to the sentry server.
/// If null or an empty list is used, the SDK will send all transactions.
/// To use regex add the `^` and the `$` to the string.
martinhaintz marked this conversation as resolved.
Show resolved Hide resolved
List<String> ignoreTransactions = [];

final List<String> _inAppExcludes = [];
Expand Down
9 changes: 9 additions & 0 deletions dart/lib/src/utils/regex_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:meta/meta.dart';

@internal
bool isMatchingRegexPattern(String value, List<String> regexPattern,
martinhaintz marked this conversation as resolved.
Show resolved Hide resolved
{bool caseSensitive = false}) {
final combinedRegexPattern = regexPattern.join('|');
final regExp = RegExp(combinedRegexPattern, caseSensitive: caseSensitive);
return regExp.hasMatch(value);
}
24 changes: 24 additions & 0 deletions dart/test/utils/regex_utils_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:sentry/src/utils/regex_utils.dart';
import 'package:test/test.dart';

void main() {
group('regex_utils', () {
final testString = "this is a test";

test('testString contains string pattern', () {
expect(isMatchingRegexPattern(testString, ["is"]), isTrue);
});

test('testString does not contain string pattern', () {
expect(isMatchingRegexPattern(testString, ["not"]), isFalse);
});

test('testString contains regex pattern', () {
expect(isMatchingRegexPattern(testString, ["^this.*\$"]), isTrue);
});

test('testString does not contain regex pattern', () {
expect(isMatchingRegexPattern(testString, ["^is.*\$"]), isFalse);
});
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import 'dart:html' as html show window, Window;

Check warning on line 1 in flutter/lib/src/event_processor/url_filter/html_url_filter_event_processor.dart

View workflow job for this annotation

GitHub Actions / analyze / analyze

Unused import: 'dart:html'.

Try removing the import directive. See https://dart.dev/diagnostics/unused_import to learn more about this problem.

import '../../../sentry_flutter.dart';
import 'url_filter_event_processor.dart';
// ignore: implementation_imports
import 'package:sentry/src/utils/regex_utils.dart';

// ignore_for_file: invalid_use_of_internal_member

UrlFilterEventProcessor urlFilterEventProcessor(SentryFlutterOptions options) =>
WebUrlFilterEventProcessor(options);

class WebUrlFilterEventProcessor implements UrlFilterEventProcessor {
WebUrlFilterEventProcessor(
this._options,
);

final SentryFlutterOptions _options;

@override
SentryEvent? apply(SentryEvent event, Hint hint) {
final frames = _getStacktraceFrames(event);
final lastPath = frames?.first?.absPath;

if (lastPath == null) {
return event;
}
Comment on lines +23 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have you tried if this works with a release build?

you'll also need the sentry_dart_plugin to upload source maps if you haven't


if (_options.allowUrls.isNotEmpty &&
!isMatchingRegexPattern(lastPath, _options.allowUrls)) {
return null;
}

if (_options.denyUrls.isNotEmpty &&
isMatchingRegexPattern(lastPath, _options.denyUrls)) {
return null;
}

return event;
}

Iterable<SentryStackFrame?>? _getStacktraceFrames(SentryEvent event) {
if (event.exceptions?.isNotEmpty == true) {
return event.exceptions?.first.stackTrace?.frames;
}
if (event.threads?.isNotEmpty == true) {
final stacktraces = event.threads?.map((e) => e.stacktrace);
return stacktraces
?.where((element) => element != null)
.expand((element) => element!.frames);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import '../../../sentry_flutter.dart';
import 'url_filter_event_processor.dart';

UrlFilterEventProcessor urlFilterEventProcessor(SentryFlutterOptions _) =>
IoUrlFilterEventProcessor();

class IoUrlFilterEventProcessor implements UrlFilterEventProcessor {
@override
SentryEvent apply(SentryEvent event, Hint hint) => event;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import '../../../sentry_flutter.dart';
import 'io_url_filter_event_processor.dart'
if (dart.library.html) 'html_url_filter_event_processor.dart'
if (dart.library.js_interop) 'web_url_filter_event_processor.dart';

abstract class UrlFilterEventProcessor implements EventProcessor {
factory UrlFilterEventProcessor(SentryFlutterOptions options) =>
urlFilterEventProcessor(options);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// We would lose compatibility with old dart versions by adding web to pubspec.
// ignore: depend_on_referenced_packages
import 'package:web/web.dart' as web show window, Window;

Check warning on line 3 in flutter/lib/src/event_processor/url_filter/web_url_filter_event_processor.dart

View workflow job for this annotation

GitHub Actions / analyze / analyze

Unused import: 'package:web/web.dart'.

Try removing the import directive. See https://dart.dev/diagnostics/unused_import to learn more about this problem.
Copy link
Contributor

@buenaflor buenaflor Aug 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we are accessing window, do we need to create two separate event processors here, a html event processor and web event processor to keep compat with wasm? @vaind

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd have expected CI to fail as it is. Actually, it seems like we don't run wasm tests on flutter test. Let me fix that: #2231


import '../../../sentry_flutter.dart';
import 'url_filter_event_processor.dart';
// ignore: implementation_imports
import 'package:sentry/src/utils/regex_utils.dart';

// ignore_for_file: invalid_use_of_internal_member

UrlFilterEventProcessor urlFilterEventProcessor(SentryFlutterOptions options) =>
WebUrlFilterEventProcessor(options);

class WebUrlFilterEventProcessor implements UrlFilterEventProcessor {
WebUrlFilterEventProcessor(
this._options,
);

final SentryFlutterOptions _options;

@override
SentryEvent? apply(SentryEvent event, Hint hint) {
final frames = _getStacktraceFrames(event);
final lastPath = frames?.first?.absPath;

if (lastPath == null) {
return event;
}

if (_options.allowUrls.isNotEmpty &&
!isMatchingRegexPattern(lastPath, _options.allowUrls)) {
return null;
}

if (_options.denyUrls.isNotEmpty &&
isMatchingRegexPattern(lastPath, _options.denyUrls)) {
return null;
}

return event;
}

Iterable<SentryStackFrame?>? _getStacktraceFrames(SentryEvent event) {
if (event.exceptions?.isNotEmpty == true) {
return event.exceptions?.first.stackTrace?.frames;
}
if (event.threads?.isNotEmpty == true) {
final stacktraces = event.threads?.map((e) => e.stacktrace);
return stacktraces
?.where((element) => element != null)
.expand((element) => element!.frames);
}
return null;
}
}
2 changes: 2 additions & 0 deletions flutter/lib/src/sentry_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'event_processor/android_platform_exception_event_processor.dart';
import 'event_processor/flutter_enricher_event_processor.dart';
import 'event_processor/flutter_exception_event_processor.dart';
import 'event_processor/platform_exception_event_processor.dart';
import 'event_processor/url_filter/url_filter_event_processor.dart';
import 'event_processor/widget_event_processor.dart';
import 'file_system_transport.dart';
import 'flutter_exception_type_identifier.dart';
Expand Down Expand Up @@ -131,6 +132,7 @@ mixin SentryFlutter {

options.addEventProcessor(FlutterEnricherEventProcessor(options));
options.addEventProcessor(WidgetEventProcessor());
options.addEventProcessor(UrlFilterEventProcessor(options));

if (options.platformChecker.platform.isAndroid) {
options.addEventProcessor(
Expand Down
15 changes: 15 additions & 0 deletions flutter/lib/src/sentry_flutter_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,21 @@ class SentryFlutterOptions extends SentryOptions {
/// See https://api.flutter.dev/flutter/foundation/FlutterErrorDetails/silent.html
bool reportSilentFlutterErrors = false;

/// (Web only) Events only occurring on these Urls will be handled and sent to sentry.
/// If an empty list is used, the SDK will send all errors.
/// `allowUrls` uses regex for the matching.
///
/// If used on a platform other than Web, this setting will be ignored.
List<String> allowUrls = [];

/// (Web only) Events occurring on these Urls will be ignored and are not sent to sentry.
/// If an empty list is used, the SDK will send all errors.
/// `denyUrls` uses regex for the matching.
/// In combination with `allowUrls` you can block subdomains of the domains listed in `allowUrls`.
///
/// If used on a platform other than Web, this setting will be ignored.
List<String> denyUrls = [];

/// Enables Out of Memory Tracking for iOS and macCatalyst.
/// See the following link for more information and possible restrictions:
/// https://docs.sentry.io/platforms/apple/guides/ios/configuration/out-of-memory/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@TestOn('vm')
library flutter_test;

import 'package:flutter_test/flutter_test.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sentry_flutter/src/event_processor/url_filter/url_filter_event_processor.dart';

void main() {
group("ignore allowUrls and denyUrls for non Web", () {
late Fixture fixture;

setUp(() async {
fixture = Fixture();
});

test('returns the event and ignore allowUrls and denyUrls for non Web',
() async {
SentryEvent? event = SentryEvent(
request: SentryRequest(
url: 'another.url/for/a/special/test/testing/this-feature',
),
);
fixture.options.allowUrls = ["^this.is/.*\$"];
fixture.options.denyUrls = ["special"];

var eventProcessor = fixture.getSut();
event = await eventProcessor.apply(event, Hint());

expect(event, isNotNull);
});
});
}

class Fixture {
SentryFlutterOptions options = SentryFlutterOptions();
UrlFilterEventProcessor getSut() {
return UrlFilterEventProcessor(options);
}
}
Loading
Loading