diff --git a/.github/workflows/flutter_integration_test.yml b/.github/workflows/flutter_integration_test.yml index 37c071bd02..9a78828164 100644 --- a/.github/workflows/flutter_integration_test.yml +++ b/.github/workflows/flutter_integration_test.yml @@ -48,16 +48,16 @@ jobs: - name: flutter pub get run: flutter pub get - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - - name: AVD cache - uses: actions/cache@v3 - id: avd-cache - with: - path: | - ~/.android/avd/* - ~/.android/adb* + - name: Gradle cache + uses: gradle/gradle-build-action@v2 + + - name: AVD cache + uses: actions/cache@v3 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* key: avd-21 - name: create AVD and generate snapshot for caching @@ -73,17 +73,17 @@ jobs: profile: Nexus 6 script: echo 'Generated AVD snapshot for caching.' - - name: launch android emulator & run android integration test - uses: reactivecircus/android-emulator-runner@d94c3fbe4fe6a29e4a5ba47c12fb47677c73656b #pin@v2.28.0 - with: - working-directory: ./flutter/example - api-level: 21 - force-avd-creation: false - emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none - disable-animations: true - arch: x86_64 - profile: Nexus 6 - script: flutter test integration_test/integration_test.dart --verbose + - name: launch android emulator & run android integration test + uses: reactivecircus/android-emulator-runner@d94c3fbe4fe6a29e4a5ba47c12fb47677c73656b #pin@v2.28.0 + with: + working-directory: ./flutter/example + api-level: 21 + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + arch: x86_64 + profile: Nexus 6 + script: flutter test integration_test/integration_test.dart --verbose test-ios: runs-on: macos-13 diff --git a/CHANGELOG.md b/CHANGELOG.md index 37fa04c4e3..323f9c563e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,24 @@ # Changelog -## Unreleased +## 8.0.0 + +### Breaking Changes +- Mark exceptions not handled by the user as `handled: false` ([#1535](https://github.com/getsentry/sentry-dart/pull/1535)) + - This will affect your release health data, and is therefore considered a breaking change. +- Refrain from overwriting the span status for unfinished spans ([#1577](https://github.com/getsentry/sentry-dart/pull/1577)) + - Older self-hosted sentry instances will drop transactions containing unfinished spans. + - This change was introduced in [relay/#1690](https://github.com/getsentry/relay/pull/1690) and released with [22.12.0](https://github.com/getsentry/relay/releases/tag/22.12.0) +- Do not leak extensions of external classes ([#1576](https://github.com/getsentry/sentry-dart/pull/1576)) +- Make `hint` non-nullable in `BeforeSendCallback`, `BeforeBreadcrumbCall` and `EventProcessor` ([#1574](https://github.com/getsentry/sentry-dart/pull/1574)) + - This will affect your callbacks, making this a breaking change. +- Load Device Contexts from Sentry Java ([#1616](https://github.com/getsentry/sentry-dart/pull/1616)) + - Now the device context from Android is available in `BeforeSendCallback` +- Set ip_address to {{auto}} by default, even if sendDefaultPII is disabled ([#1665](https://github.com/getsentry/sentry-dart/pull/1665)) + - Instead use the "Prevent Storing of IP Addresses" option in the "Security & Privacy" project settings on sentry.io + +## Unreleased + ### Fixes - Fixing memory leak issue in SentryFlutterPlugin (Android Plugin) ([#1588](https://github.com/getsentry/sentry-dart/pull/1588)) diff --git a/dart/example/bin/example.dart b/dart/example/bin/example.dart index 5163f341f7..d7530f5874 100644 --- a/dart/example/bin/example.dart +++ b/dart/example/bin/example.dart @@ -104,7 +104,7 @@ Future decode() async { class TagEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, hint) { return event..tags?.addAll({'page-locale': 'en-us'}); } } diff --git a/dart/example_web/web/main.dart b/dart/example_web/web/main.dart index c396be5e83..3034effe9b 100644 --- a/dart/example_web/web/main.dart +++ b/dart/example_web/web/main.dart @@ -129,7 +129,7 @@ Future parseData() async { class TagEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return event..tags?.addAll({'page-locale': 'en-us'}); } } diff --git a/dart/lib/src/client_reports/discard_reason.dart b/dart/lib/src/client_reports/discard_reason.dart index 1b990f8dd2..81c3a45dd0 100644 --- a/dart/lib/src/client_reports/discard_reason.dart +++ b/dart/lib/src/client_reports/discard_reason.dart @@ -12,24 +12,3 @@ enum DiscardReason { cacheOverflow, rateLimitBackoff, } - -extension OutcomeExtension on DiscardReason { - String toStringValue() { - switch (this) { - case DiscardReason.beforeSend: - return 'before_send'; - case DiscardReason.eventProcessor: - return 'event_processor'; - case DiscardReason.sampleRate: - return 'sample_rate'; - case DiscardReason.networkError: - return 'network_error'; - case DiscardReason.queueOverflow: - return 'queue_overflow'; - case DiscardReason.cacheOverflow: - return 'cache_overflow'; - case DiscardReason.rateLimitBackoff: - return 'ratelimit_backoff'; - } - } -} diff --git a/dart/lib/src/client_reports/discarded_event.dart b/dart/lib/src/client_reports/discarded_event.dart index 0b989aa4cf..1e216804c3 100644 --- a/dart/lib/src/client_reports/discarded_event.dart +++ b/dart/lib/src/client_reports/discarded_event.dart @@ -13,9 +13,53 @@ class DiscardedEvent { Map toJson() { return { - 'reason': reason.toStringValue(), - 'category': category.toStringValue(), + 'reason': reason._toStringValue(), + 'category': category._toStringValue(), 'quantity': quantity, }; } } + +extension _OutcomeExtension on DiscardReason { + String _toStringValue() { + switch (this) { + case DiscardReason.beforeSend: + return 'before_send'; + case DiscardReason.eventProcessor: + return 'event_processor'; + case DiscardReason.sampleRate: + return 'sample_rate'; + case DiscardReason.networkError: + return 'network_error'; + case DiscardReason.queueOverflow: + return 'queue_overflow'; + case DiscardReason.cacheOverflow: + return 'cache_overflow'; + case DiscardReason.rateLimitBackoff: + return 'ratelimit_backoff'; + } + } +} + +extension _DataCategoryExtension on DataCategory { + String _toStringValue() { + switch (this) { + case DataCategory.all: + return '__all__'; + case DataCategory.dataCategoryDefault: + return 'default'; + case DataCategory.error: + return 'error'; + case DataCategory.session: + return 'session'; + case DataCategory.transaction: + return 'transaction'; + case DataCategory.attachment: + return 'attachment'; + case DataCategory.security: + return 'security'; + case DataCategory.unknown: + return 'unknown'; + } + } +} diff --git a/dart/lib/src/event_processor.dart b/dart/lib/src/event_processor.dart index 94fcd77fd8..45005d7b0e 100644 --- a/dart/lib/src/event_processor.dart +++ b/dart/lib/src/event_processor.dart @@ -8,7 +8,7 @@ import 'protocol.dart'; /// null in case the event will be dropped and not sent. abstract class EventProcessor { FutureOr apply( - SentryEvent event, { - Hint? hint, - }); + SentryEvent event, + Hint hint, + ); } diff --git a/dart/lib/src/event_processor/deduplication_event_processor.dart b/dart/lib/src/event_processor/deduplication_event_processor.dart index 5c3bd4606e..8706082cf5 100644 --- a/dart/lib/src/event_processor/deduplication_event_processor.dart +++ b/dart/lib/src/event_processor/deduplication_event_processor.dart @@ -26,7 +26,7 @@ class DeduplicationEventProcessor implements EventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart b/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart index 03623d7f0b..93d2514bfa 100644 --- a/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart +++ b/dart/lib/src/event_processor/enricher/io_enricher_event_processor.dart @@ -18,7 +18,7 @@ class IoEnricherEventProcessor implements EnricherEventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { // If there's a native integration available, it probably has better // information available than Flutter. diff --git a/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart b/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart index fe2684d593..4c992b966d 100644 --- a/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart +++ b/dart/lib/src/event_processor/enricher/web_enricher_event_processor.dart @@ -21,7 +21,7 @@ class WebEnricherEventProcessor implements EnricherEventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { // Web has no native integration, so no need to check for it final contexts = event.contexts.copyWith( diff --git a/dart/lib/src/event_processor/exception/io_exception_event_processor.dart b/dart/lib/src/event_processor/exception/io_exception_event_processor.dart index 0f7763f35e..bb4049c00e 100644 --- a/dart/lib/src/event_processor/exception/io_exception_event_processor.dart +++ b/dart/lib/src/event_processor/exception/io_exception_event_processor.dart @@ -14,7 +14,7 @@ class IoExceptionEventProcessor implements ExceptionEventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { final throwable = event.throwable; if (throwable is HttpException) { return _applyHttpException(throwable, event); diff --git a/dart/lib/src/event_processor/exception/web_exception_event_processor.dart b/dart/lib/src/event_processor/exception/web_exception_event_processor.dart index ad57c9f5c2..6ce3be0fe0 100644 --- a/dart/lib/src/event_processor/exception/web_exception_event_processor.dart +++ b/dart/lib/src/event_processor/exception/web_exception_event_processor.dart @@ -8,5 +8,5 @@ ExceptionEventProcessor exceptionEventProcessor(SentryOptions _) => class WebExcptionEventProcessor implements ExceptionEventProcessor { @override - SentryEvent apply(SentryEvent event, {Hint? hint}) => event; + SentryEvent apply(SentryEvent event, Hint hint) => event; } diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 87620d7ba1..f14f69d5dc 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -11,8 +11,8 @@ import 'sentry_attachment/sentry_attachment.dart'; /// Example: /// /// ```dart -/// options.beforeSend = (event, {hint}) { -/// final syntheticException = hint?.get(TypeCheckHint.syntheticException); +/// options.beforeSend = (event, hint) { +/// final syntheticException = hint.get(TypeCheckHint.syntheticException); /// if (syntheticException is FlutterErrorDetails) { /// // Do something with hint data /// } @@ -28,14 +28,14 @@ import 'sentry_attachment/sentry_attachment.dart'; /// ```dart /// import 'dart:convert'; /// -/// options.beforeSend = (event, {hint}) { +/// options.beforeSend = (event, hint) { /// final text = 'This event should not be sent happen in prod. Investigate.'; /// final textAttachment = SentryAttachment.fromIntList( /// utf8.encode(text), /// 'event_info.txt', /// contentType: 'text/plain', /// ); -/// hint?.attachments.add(textAttachment); +/// hint.attachments.add(textAttachment); /// return event; /// }; /// ``` diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 98df59194f..d86be0328a 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -135,7 +135,7 @@ class FailedRequestClient extends BaseClient { // Only check `failedRequestStatusCodes` & `failedRequestTargets` if no exception was thrown. if (exception == null) { - if (!failedRequestStatusCodes.containsStatusCode(statusCode)) { + if (!failedRequestStatusCodes._containsStatusCode(statusCode)) { return; } if (!containsTargetOrMatchesRegExp( @@ -246,7 +246,7 @@ class FailedRequestClient extends BaseClient { } extension _ListX on List { - bool containsStatusCode(int? statusCode) { + bool _containsStatusCode(int? statusCode) { if (statusCode == null) { return false; } diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index 9689c8a974..b5ee7d003c 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; -import '../utils/iterable_extension.dart'; +import '../utils/iterable_utils.dart'; import '../utils/http_sanitizer.dart'; /// The Request interface contains information on a HTTP request related to the event. @@ -85,9 +85,10 @@ class SentryRequest { _headers = headers != null ? Map.from(headers) : null, // Look for a 'Set-Cookie' header (case insensitive) if not given. cookies = cookies ?? - headers?.entries - .firstWhereOrNull((e) => e.key.toLowerCase() == 'cookie') - ?.value, + IterableUtils.firstWhereOrNull( + headers?.entries, + (MapEntry e) => e.key.toLowerCase() == 'cookie', + )?.value, _env = env != null ? Map.from(env) : null, _other = other != null ? Map.from(other) : null; diff --git a/dart/lib/src/protocol/sentry_response.dart b/dart/lib/src/protocol/sentry_response.dart index 91faaa37eb..6008ea8730 100644 --- a/dart/lib/src/protocol/sentry_response.dart +++ b/dart/lib/src/protocol/sentry_response.dart @@ -1,6 +1,6 @@ import 'package:meta/meta.dart'; import 'contexts.dart'; -import '../utils/iterable_extension.dart'; +import '../utils/iterable_utils.dart'; /// The response interface contains information on a HTTP request related to the event. @immutable @@ -53,9 +53,11 @@ class SentryResponse { _headers = headers != null ? Map.from(headers) : null, // Look for a 'Set-Cookie' header (case insensitive) if not given. cookies = cookies ?? - headers?.entries - .firstWhereOrNull((e) => e.key.toLowerCase() == 'set-cookie') - ?.value; + IterableUtils.firstWhereOrNull( + headers?.entries, + (MapEntry e) => + e.key.toLowerCase() == 'set-cookie', + )?.value; /// Deserializes a [SentryResponse] from JSON [Map]. factory SentryResponse.fromJson(Map json) { diff --git a/dart/lib/src/run_zoned_guarded_integration.dart b/dart/lib/src/run_zoned_guarded_integration.dart index ba70fc2472..623a9a5f54 100644 --- a/dart/lib/src/run_zoned_guarded_integration.dart +++ b/dart/lib/src/run_zoned_guarded_integration.dart @@ -44,8 +44,8 @@ class RunZonedGuardedIntegration extends Integration { stackTrace: stackTrace, ); - // runZonedGuarded doesn't crash the App. - final mechanism = Mechanism(type: 'runZonedGuarded', handled: true); + // runZonedGuarded doesn't crash the app, but is not handled by the user. + final mechanism = Mechanism(type: 'runZonedGuarded', handled: false); final throwableMechanism = ThrowableMechanism(mechanism, exception); final event = SentryEvent( diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart index f9cb3796aa..bbe8bb54d5 100644 --- a/dart/lib/src/scope.dart +++ b/dart/lib/src/scope.dart @@ -143,7 +143,7 @@ class Scope { Scope(this._options); - Breadcrumb? _addBreadCrumbSync(Breadcrumb breadcrumb, {Hint? hint}) { + Breadcrumb? _addBreadCrumbSync(Breadcrumb breadcrumb, Hint hint) { // bail out if maxBreadcrumbs is zero if (_options.maxBreadcrumbs == 0) { return null; @@ -155,7 +155,7 @@ class Scope { try { processedBreadcrumb = _options.beforeBreadcrumb!( processedBreadcrumb, - hint: hint, + hint, ); if (processedBreadcrumb == null) { _options.logger( @@ -189,7 +189,7 @@ class Scope { /// Adds a breadcrumb to the breadcrumbs queue Future addBreadcrumb(Breadcrumb breadcrumb, {Hint? hint}) async { - final addedBreadcrumb = _addBreadCrumbSync(breadcrumb, hint: hint); + final addedBreadcrumb = _addBreadCrumbSync(breadcrumb, hint ?? Hint()); if (addedBreadcrumb != null) { await _callScopeObservers((scopeObserver) async => await scopeObserver.addBreadcrumb(addedBreadcrumb)); @@ -275,9 +275,9 @@ class Scope { } Future applyToEvent( - SentryEvent event, { - Hint? hint, - }) async { + SentryEvent event, + Hint hint, + ) async { event = event.copyWith( transaction: event.transaction ?? transaction, user: _mergeUsers(user, event.user), @@ -320,7 +320,7 @@ class Scope { SentryEvent? processedEvent = event; for (final processor in _eventProcessors) { try { - final e = processor.apply(processedEvent!, hint: hint); + final e = processor.apply(processedEvent!, hint); if (e is Future) { processedEvent = await e; } else { @@ -429,7 +429,7 @@ class Scope { } for (final breadcrumb in List.from(_breadcrumbs)) { - clone._addBreadCrumbSync(breadcrumb); + clone._addBreadCrumbSync(breadcrumb, Hint()); } for (final eventProcessor in List.from(_eventProcessors)) { diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 09f98e4d02..d354e4a449 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -23,8 +23,7 @@ import 'client_reports/discard_reason.dart'; import 'transport/data_category.dart'; /// Default value for [User.ipAddress]. It gets set when an event does not have -/// a user and IP address. Only applies if [SentryOptions.sendDefaultPii] is set -/// to true. +/// a user and IP address. const _defaultIpAddress = '{{auto}}'; /// Logs crash reports and events to the Sentry.io service. @@ -76,7 +75,7 @@ class SentryClient { hint ??= Hint(); if (scope != null) { - preparedEvent = await scope.applyToEvent(preparedEvent, hint: hint); + preparedEvent = await scope.applyToEvent(preparedEvent, hint); } else { _options.logger( SentryLevel.debug, 'No scope to apply on event was provided'); @@ -89,8 +88,8 @@ class SentryClient { preparedEvent = await _runEventProcessors( preparedEvent, + hint, eventProcessors: _options.eventProcessors, - hint: hint, ); // dropped by event processors @@ -100,7 +99,7 @@ class SentryClient { preparedEvent = await _runBeforeSend( preparedEvent, - hint: hint, + hint, ); // dropped by beforeSend @@ -108,8 +107,6 @@ class SentryClient { return _sentryId; } - preparedEvent = _eventWithoutBreadcrumbsIfNeeded(preparedEvent); - var attachments = List.from(scope?.attachments ?? []); attachments.addAll(hint.attachments); var screenshot = hint.screenshot; @@ -144,7 +141,7 @@ class SentryClient { platform: event.platform ?? sdkPlatform(_options.platformChecker.isWeb), ); - event = _applyDefaultPii(event); + event = _createUserOrSetDefaultIpAddress(event); if (event is SentryTransaction) { return event; @@ -224,20 +221,13 @@ class SentryClient { return event; } - /// This modifies the users IP address according - /// to [SentryOptions.sendDefaultPii]. - SentryEvent _applyDefaultPii(SentryEvent event) { - if (!_options.sendDefaultPii) { - return event; - } + SentryEvent _createUserOrSetDefaultIpAddress(SentryEvent event) { var user = event.user; if (user == null) { - user = SentryUser(ipAddress: _defaultIpAddress); - return event.copyWith(user: user); + return event.copyWith(user: SentryUser(ipAddress: _defaultIpAddress)); } else if (event.user?.ipAddress == null) { return event.copyWith(user: user.copyWith(ipAddress: _defaultIpAddress)); } - return event; } @@ -288,9 +278,11 @@ class SentryClient { SentryTransaction? preparedTransaction = _prepareEvent(transaction) as SentryTransaction; + final hint = Hint(); + if (scope != null) { - preparedTransaction = - await scope.applyToEvent(preparedTransaction) as SentryTransaction?; + preparedTransaction = await scope.applyToEvent(preparedTransaction, hint) + as SentryTransaction?; } else { _options.logger( SentryLevel.debug, 'No scope to apply on transaction was provided'); @@ -303,6 +295,7 @@ class SentryClient { preparedTransaction = await _runEventProcessors( preparedTransaction, + hint, eventProcessors: _options.eventProcessors, ) as SentryTransaction?; @@ -312,15 +305,13 @@ class SentryClient { } preparedTransaction = - await _runBeforeSend(preparedTransaction) as SentryTransaction?; + await _runBeforeSend(preparedTransaction, hint) as SentryTransaction?; // dropped by beforeSendTransaction if (preparedTransaction == null) { return _sentryId; } - preparedTransaction = _eventWithoutBreadcrumbsIfNeeded(preparedTransaction); - final attachments = scope?.attachments .where((element) => element.addToTransactions) .toList(); @@ -354,9 +345,9 @@ class SentryClient { void close() => _options.httpClient.close(); Future _runBeforeSend( - SentryEvent event, { - Hint? hint, - }) async { + SentryEvent event, + Hint hint, + ) async { SentryEvent? eventOrTransaction = event; final beforeSend = _options.beforeSend; @@ -373,7 +364,7 @@ class SentryClient { eventOrTransaction = e; } } else if (beforeSend != null) { - final e = beforeSend(event, hint: hint); + final e = beforeSend(event, hint); if (e is Future) { eventOrTransaction = await e; } else { @@ -404,14 +395,14 @@ class SentryClient { } Future _runEventProcessors( - SentryEvent event, { - Hint? hint, + SentryEvent event, + Hint hint, { required List eventProcessors, }) async { SentryEvent? processedEvent = event; for (final processor in eventProcessors) { try { - final e = processor.apply(processedEvent!, hint: hint); + final e = processor.apply(processedEvent!, hint); if (e is Future) { processedEvent = await e; } else { @@ -454,40 +445,6 @@ class SentryClient { _options.recorder.recordLostEvent(reason, category); } - T _eventWithoutBreadcrumbsIfNeeded(T event) { - if (_shouldRemoveBreadcrumbs(event)) { - return event.copyWith(breadcrumbs: []) as T; - } else { - return event; - } - } - - /// We do this to avoid duplicate breadcrumbs on Android as sentry-android applies the breadcrumbs - /// from the native scope onto every envelope sent through it. This scope will contain the breadcrumbs - /// sent through the scope sync feature. This causes duplicate breadcrumbs. - /// We then remove the breadcrumbs in all cases but if it is handled == false, - /// this is a signal that the app would crash and android would lose the breadcrumbs by the time the app is restarted to read - /// the envelope. - bool _shouldRemoveBreadcrumbs(SentryEvent event) { - if (_options.platformChecker.isWeb) { - return false; - } - - final isAndroid = _options.platformChecker.platform.isAndroid; - final enableScopeSync = _options.enableScopeSync; - - if (!isAndroid || !enableScopeSync) { - return false; - } - - final mechanisms = - (event.exceptions ?? []).map((e) => e.mechanism).whereType(); - final hasNoMechanism = mechanisms.isEmpty; - final hasOnlyHandledMechanism = - mechanisms.every((e) => (e.handled ?? true)); - return hasNoMechanism || hasOnlyHandledMechanism; - } - Future _attachClientReportsAndSend(SentryEnvelope envelope) { final clientReport = _options.recorder.flush(); envelope.addClientReport(clientReport); diff --git a/dart/lib/src/sentry_isolate.dart b/dart/lib/src/sentry_isolate.dart index 898904cd27..8a6b71d48f 100644 --- a/dart/lib/src/sentry_isolate.dart +++ b/dart/lib/src/sentry_isolate.dart @@ -69,9 +69,10 @@ class SentryIsolate { stackTrace == null ? null : StackTrace.fromString(stackTrace), ); - // Isolate errors don't crash the App. - final mechanism = Mechanism(type: 'isolateError', handled: true); + // Isolate errors don't crash the app, but is not handled by the user. + final mechanism = Mechanism(type: 'isolateError', handled: false); final throwableMechanism = ThrowableMechanism(mechanism, throwable); + final event = SentryEvent( throwable: throwableMechanism, level: SentryLevel.fatal, diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 55450be9dd..37f7dc01e9 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -444,9 +444,9 @@ class SentryOptions { /// This function is called with an SDK specific event object and can return a modified event /// object or nothing to skip reporting the event typedef BeforeSendCallback = FutureOr Function( - SentryEvent event, { - Hint? hint, -}); + SentryEvent event, + Hint hint, +); /// This function is called with an SDK specific transaction object and can return a modified transaction /// object or nothing to skip reporting the transaction @@ -457,9 +457,9 @@ typedef BeforeSendTransactionCallback = FutureOr Function( /// This function is called with an SDK specific breadcrumb object before the breadcrumb is added /// to the scope. When nothing is returned from the function, the breadcrumb is dropped typedef BeforeBreadcrumbCallback = Breadcrumb? Function( - Breadcrumb? breadcrumb, { - Hint? hint, -}); + Breadcrumb? breadcrumb, + Hint hint, +); /// Used to provide timestamp for logging. typedef ClockProvider = DateTime Function(); diff --git a/dart/lib/src/sentry_tracer.dart b/dart/lib/src/sentry_tracer.dart index 2ca82a91ca..30a9eb27d3 100644 --- a/dart/lib/src/sentry_tracer.dart +++ b/dart/lib/src/sentry_tracer.dart @@ -85,15 +85,6 @@ class SentryTracer extends ISentrySpan { _children.removeWhere( (span) => !_hasSpanSuitableTimestamps(span, commonEndTimestamp)); - // finish unfinished spans otherwise transaction gets dropped - final spansToBeFinished = _children.where((span) => !span.finished); - for (final span in spansToBeFinished) { - await span.finish( - status: SpanStatus.deadlineExceeded(), - endTimestamp: commonEndTimestamp, - ); - } - var _rootEndTimestamp = commonEndTimestamp; if (_trimEnd && children.isNotEmpty) { final childEndTimestamps = children diff --git a/dart/lib/src/transport/data_category.dart b/dart/lib/src/transport/data_category.dart index 1843acfacb..38340e2630 100644 --- a/dart/lib/src/transport/data_category.dart +++ b/dart/lib/src/transport/data_category.dart @@ -9,46 +9,3 @@ enum DataCategory { security, unknown } - -extension DataCategoryExtension on DataCategory { - static DataCategory fromStringValue(String stringValue) { - switch (stringValue) { - case '__all__': - return DataCategory.all; - case 'default': - return DataCategory.dataCategoryDefault; - case 'error': - return DataCategory.error; - case 'session': - return DataCategory.session; - case 'transaction': - return DataCategory.transaction; - case 'attachment': - return DataCategory.attachment; - case 'security': - return DataCategory.security; - } - return DataCategory.unknown; - } - - String toStringValue() { - switch (this) { - case DataCategory.all: - return '__all__'; - case DataCategory.dataCategoryDefault: - return 'default'; - case DataCategory.error: - return 'error'; - case DataCategory.session: - return 'session'; - case DataCategory.transaction: - return 'transaction'; - case DataCategory.attachment: - return 'attachment'; - case DataCategory.security: - return 'security'; - case DataCategory.unknown: - return 'unknown'; - } - } -} diff --git a/dart/lib/src/transport/rate_limit_parser.dart b/dart/lib/src/transport/rate_limit_parser.dart index 63f4f179d1..a7ddadc52c 100644 --- a/dart/lib/src/transport/rate_limit_parser.dart +++ b/dart/lib/src/transport/rate_limit_parser.dart @@ -29,7 +29,8 @@ class RateLimitParser { if (allCategories.isNotEmpty) { final categoryValues = allCategories.split(';'); for (final categoryValue in categoryValues) { - final category = DataCategoryExtension.fromStringValue(categoryValue); + final category = + _DataCategoryExtension._fromStringValue(categoryValue); if (category != DataCategory.unknown) { rateLimits.add(RateLimit(category, duration)); } @@ -56,3 +57,25 @@ class RateLimitParser { } } } + +extension _DataCategoryExtension on DataCategory { + static DataCategory _fromStringValue(String stringValue) { + switch (stringValue) { + case '__all__': + return DataCategory.all; + case 'default': + return DataCategory.dataCategoryDefault; + case 'error': + return DataCategory.error; + case 'session': + return DataCategory.session; + case 'transaction': + return DataCategory.transaction; + case 'attachment': + return DataCategory.attachment; + case 'security': + return DataCategory.security; + } + return DataCategory.unknown; + } +} diff --git a/dart/lib/src/utils/http_sanitizer.dart b/dart/lib/src/utils/http_sanitizer.dart index c131cc0c4e..2e5de505a9 100644 --- a/dart/lib/src/utils/http_sanitizer.dart +++ b/dart/lib/src/utils/http_sanitizer.dart @@ -60,7 +60,7 @@ class HttpSanitizer { } } -extension UriPath on Uri { +extension _UriPath on Uri { String _urlWithRedactedAuth() { var buffer = ''; if (scheme.isNotEmpty) { @@ -78,6 +78,7 @@ extension UriPath on Uri { } } +@internal extension SanitizedSentryRequest on SentryRequest { SentryRequest sanitized() { final urlDetails = HttpSanitizer.sanitizeUrl(url) ?? UrlDetails(); diff --git a/dart/lib/src/utils/isolate_utils.dart b/dart/lib/src/utils/isolate_utils.dart index ce523b0d63..3e9c4b20bc 100644 --- a/dart/lib/src/utils/isolate_utils.dart +++ b/dart/lib/src/utils/isolate_utils.dart @@ -1,4 +1,7 @@ +import 'package:meta/meta.dart'; + import '_io_get_isolate_name.dart' if (dart.library.html) '_web_get_isolate_name.dart' as isolate_getter; +@internal String? getIsolateName() => isolate_getter.getIsolateName(); diff --git a/dart/lib/src/utils/iterable_extension.dart b/dart/lib/src/utils/iterable_extension.dart deleted file mode 100644 index 34c2c60943..0000000000 --- a/dart/lib/src/utils/iterable_extension.dart +++ /dev/null @@ -1,8 +0,0 @@ -extension IterableExtension on Iterable { - T? firstWhereOrNull(bool Function(T item) predicate) { - for (var item in this) { - if (predicate(item)) return item; - } - return null; - } -} diff --git a/dart/lib/src/utils/iterable_utils.dart b/dart/lib/src/utils/iterable_utils.dart new file mode 100644 index 0000000000..c2fb5e5c69 --- /dev/null +++ b/dart/lib/src/utils/iterable_utils.dart @@ -0,0 +1,17 @@ +import 'package:meta/meta.dart'; + +@internal +class IterableUtils { + static T? firstWhereOrNull( + Iterable? iterable, + bool Function(T item) test, + ) { + if (iterable == null) { + return null; + } + for (var item in iterable) { + if (test(item)) return item; + } + return null; + } +} diff --git a/dart/test/event_processor/deduplication_event_processor_test.dart b/dart/test/event_processor/deduplication_event_processor_test.dart index 47540cf035..4ced85c113 100644 --- a/dart/test/event_processor/deduplication_event_processor_test.dart +++ b/dart/test/event_processor/deduplication_event_processor_test.dart @@ -15,16 +15,16 @@ void main() { final sut = fixture.getSut(true); var ogEvent = _createEvent('foo'); - expect(sut.apply(ogEvent), isNotNull); - expect(sut.apply(ogEvent), isNull); + expect(sut.apply(ogEvent, Hint()), isNotNull); + expect(sut.apply(ogEvent, Hint()), isNull); }); test('does not deduplicate if disabled', () { final sut = fixture.getSut(false); var ogEvent = _createEvent('foo'); - expect(sut.apply(ogEvent), isNotNull); - expect(sut.apply(ogEvent), isNotNull); + expect(sut.apply(ogEvent, Hint()), isNotNull); + expect(sut.apply(ogEvent, Hint()), isNotNull); }); test('does not deduplicate if different events', () { @@ -32,16 +32,16 @@ void main() { var fooEvent = _createEvent('foo'); var barEvent = _createEvent('bar'); - expect(sut.apply(fooEvent), isNotNull); - expect(sut.apply(barEvent), isNotNull); + expect(sut.apply(fooEvent, Hint()), isNotNull); + expect(sut.apply(barEvent, Hint()), isNotNull); }); test('does not deduplicate transaction', () { final sut = fixture.getSut(true); final transaction = _createTransaction(fixture.hub); - expect(sut.apply(transaction), isNotNull); - expect(sut.apply(transaction), isNotNull); + expect(sut.apply(transaction, Hint()), isNotNull); + expect(sut.apply(transaction, Hint()), isNotNull); }); test('exceptions to keep for deduplication', () { @@ -51,10 +51,10 @@ void main() { var barEvent = _createEvent('bar'); var fooBarEvent = _createEvent('foo bar'); - expect(sut.apply(fooEvent), isNotNull); - expect(sut.apply(barEvent), isNotNull); - expect(sut.apply(fooBarEvent), isNotNull); - expect(sut.apply(fooEvent), isNotNull); + expect(sut.apply(fooEvent, Hint()), isNotNull); + expect(sut.apply(barEvent, Hint()), isNotNull); + expect(sut.apply(fooBarEvent, Hint()), isNotNull); + expect(sut.apply(fooEvent, Hint()), isNotNull); }); test('integration test', () async { diff --git a/dart/test/event_processor/enricher/io_enricher_test.dart b/dart/test/event_processor/enricher/io_enricher_test.dart index eb4a821de7..fcf37f958e 100644 --- a/dart/test/event_processor/enricher/io_enricher_test.dart +++ b/dart/test/event_processor/enricher/io_enricher_test.dart @@ -17,7 +17,7 @@ void main() { test('adds dart runtime', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.runtimes, isNotEmpty); final dartRuntime = event?.contexts.runtimes @@ -31,7 +31,7 @@ void main() { var event = SentryEvent(contexts: Contexts(runtimes: [runtime])); final enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.contexts.runtimes.contains(runtime), true); // second runtime is Dart runtime @@ -42,7 +42,7 @@ void main() { 'does not add device, os and culture if native integration is available', () { final enricher = fixture.getSut(hasNativeIntegration: true); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNull); expect(event?.contexts.operatingSystem, isNull); @@ -52,7 +52,7 @@ void main() { test('adds device, os and culture if no native integration is available', () { final enricher = fixture.getSut(hasNativeIntegration: false); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNotNull); expect(event?.contexts.operatingSystem, isNotNull); @@ -61,14 +61,14 @@ void main() { test('device has name', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device?.name, isNotNull); }); test('culture has locale and timezone', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.culture?.locale, isNotNull); expect(event?.contexts.culture?.timezone, isNotNull); @@ -76,7 +76,7 @@ void main() { test('os has name and version', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.operatingSystem?.name, isNotNull); expect(event?.contexts.operatingSystem?.version, isNotNull); @@ -84,7 +84,7 @@ void main() { test('adds Dart context with PII', () { final enricher = fixture.getSut(includePii: true); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); final dartContext = event?.contexts['dart_context']; expect(dartContext, isNotNull); @@ -97,7 +97,7 @@ void main() { test('adds Dart context without PII', () { final enricher = fixture.getSut(includePii: false); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); final dartContext = event?.contexts['dart_context']; expect(dartContext, isNotNull); @@ -131,7 +131,7 @@ void main() { hasNativeIntegration: false, ); - final event = enricher.apply(fakeEvent); + final event = enricher.apply(fakeEvent, Hint()); // contexts.device expect( diff --git a/dart/test/event_processor/enricher/web_enricher_test.dart b/dart/test/event_processor/enricher/web_enricher_test.dart index 60076e506a..e5d5b2efec 100644 --- a/dart/test/event_processor/enricher/web_enricher_test.dart +++ b/dart/test/event_processor/enricher/web_enricher_test.dart @@ -20,21 +20,21 @@ void main() { test('add path as transaction if transaction is null', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.transaction, isNotNull); }); test("don't overwrite transaction", () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent(transaction: 'foobar')); + final event = enricher.apply(SentryEvent(transaction: 'foobar'), Hint()); expect(event?.transaction, 'foobar'); }); test('add request with user-agent header', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.request?.headers['User-Agent'], isNotNull); expect(event?.request?.url, isNotNull); @@ -50,7 +50,7 @@ void main() { ), ); var enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.request?.headers['User-Agent'], isNotNull); expect(event.request?.headers['foo'], 'bar'); @@ -68,7 +68,7 @@ void main() { ), ); var enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.request?.headers['Authorization'], isNull); expect(event.request?.headers['authorization'], isNull); @@ -84,7 +84,7 @@ void main() { ), ); var enricher = fixture.getSut(); - event = enricher.apply(event)!; + event = enricher.apply(event, Hint())!; expect(event.request?.headers['User-Agent'], 'best browser agent'); expect(event.request?.url, 'foo.bar'); @@ -92,14 +92,14 @@ void main() { test('adds device and os', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNotNull); }); test('adds Dart context', () { final enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); final dartContext = event?.contexts['dart_context']; expect(dartContext, isNotNull); @@ -108,14 +108,14 @@ void main() { test('device has screendensity', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device?.screenDensity, isNotNull); }); test('culture has timezone', () { var enricher = fixture.getSut(); - final event = enricher.apply(SentryEvent()); + final event = enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.culture?.timezone, isNotNull); }); @@ -142,7 +142,7 @@ void main() { final enricher = fixture.getSut(); - final event = enricher.apply(fakeEvent); + final event = enricher.apply(fakeEvent, Hint()); // contexts.device expect( diff --git a/dart/test/event_processor/exception/io_exception_event_processor_test.dart b/dart/test/event_processor/exception/io_exception_event_processor_test.dart index 14d2720df2..5d4d771a08 100644 --- a/dart/test/event_processor/exception/io_exception_event_processor_test.dart +++ b/dart/test/event_processor/exception/io_exception_event_processor_test.dart @@ -23,6 +23,7 @@ void main() { uri: Uri.parse('https://example.org/foo/bar?foo=bar'), ), ), + Hint(), ); expect(event?.request, isNotNull); @@ -36,6 +37,7 @@ void main() { SentryEvent( throwable: HttpException(''), ), + Hint(), ); expect(event?.request, isNull); @@ -55,6 +57,7 @@ void main() { ), ), ), + Hint(), ); expect(event?.request, isNotNull); @@ -81,6 +84,7 @@ void main() { OSError('Oh no :(', 42), ), ), + Hint(), ); // Due to the test setup, there's no SentryException for the FileSystemException. diff --git a/dart/test/http_client/failed_request_client_test.dart b/dart/test/http_client/failed_request_client_test.dart index 4e6cac15b1..2d017c177d 100644 --- a/dart/test/http_client/failed_request_client_test.dart +++ b/dart/test/http_client/failed_request_client_test.dart @@ -295,7 +295,7 @@ void main() { final sut = fixture.getSut(client: client); Hint? eventHint; - fixture.options.addEventProcessor(FunctionEventProcessor((event, {hint}) { + fixture.options.addEventProcessor(FunctionEventProcessor((event, hint) { eventHint = hint; return event; })); diff --git a/dart/test/mocks.dart b/dart/test/mocks.dart index 82430d96e8..08058d3b32 100644 --- a/dart/test/mocks.dart +++ b/dart/test/mocks.dart @@ -98,7 +98,7 @@ final fakeEvent = SentryEvent( /// Always returns null and thus drops all events class DropAllEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return null; } } @@ -109,13 +109,13 @@ class FunctionEventProcessor implements EventProcessor { final EventProcessorFunction applyFunction; @override - SentryEvent? apply(SentryEvent event, {hint}) { - return applyFunction(event, hint: hint); + SentryEvent? apply(SentryEvent event, Hint hint) { + return applyFunction(event, hint); } } -typedef EventProcessorFunction = SentryEvent? Function(SentryEvent event, - {Hint? hint}); +typedef EventProcessorFunction = SentryEvent? Function( + SentryEvent event, Hint hint); var fakeEnvelope = SentryEnvelope.fromEvent( fakeEvent, diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart index e8d2e08bf9..d93b1cf112 100644 --- a/dart/test/scope_test.dart +++ b/dart/test/scope_test.dart @@ -98,6 +98,26 @@ void main() { expect(sut.breadcrumbs.last, breadcrumb); }); + test('beforeBreadcrumb called with user provided hint', () { + Hint? actual; + BeforeBreadcrumbCallback bb = (_, hint) { + actual = hint; + return null; + }; + final sut = fixture.getSut( + beforeBreadcrumbCallback: bb, + ); + + final breadcrumb = Breadcrumb( + message: 'test log', + timestamp: DateTime.utc(2019), + ); + final hint = Hint.withMap({'user-name': 'joe dirt'}); + sut.addBreadcrumb(breadcrumb, hint: hint); + + expect(actual?.get('user-name'), 'joe dirt'); + }); + test('Executes and drops $Breadcrumb', () { final sut = fixture.getSut( beforeBreadcrumbCallback: fixture.beforeBreadcrumbCallback, @@ -404,7 +424,7 @@ void main() { await scope.setContexts('theme', 'material'); await scope.setUser(scopeUser); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.user, scopeUser); expect(updatedEvent?.transaction, '/example/app'); @@ -425,7 +445,7 @@ void main() { final scope = Scope(SentryOptions(dsn: fakeDsn)) ..span = fixture.sentryTracer; - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.contexts['trace'] is SentryTraceContext, true); }); @@ -448,7 +468,7 @@ void main() { await scope.addBreadcrumb(breadcrumb); await scope.setUser(scopeUser); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.user, isNotNull); expect(updatedEvent?.user?.id, eventUser.id); @@ -496,7 +516,7 @@ void main() { SentryOperatingSystem(name: 'context-os'), ); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.contexts[SentryDevice.type].name, 'event-device'); expect(updatedEvent?.contexts[SentryApp.type].name, 'event-app'); @@ -526,7 +546,7 @@ void main() { await scope.setContexts('location', {'city': 'London'}); await scope.setContexts('items', [1, 2, 3]); - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.contexts[SentryDevice.type].name, 'context-device'); expect(updatedEvent?.contexts[SentryApp.type].name, 'context-app'); @@ -551,7 +571,7 @@ void main() { final scope = Scope(SentryOptions(dsn: fakeDsn)) ..level = SentryLevel.error; - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.level, SentryLevel.error); }); @@ -561,7 +581,7 @@ void main() { final scope = Scope(SentryOptions(dsn: fakeDsn)) ..span = fixture.sentryTracer; - final updatedEvent = await scope.applyToEvent(event); + final updatedEvent = await scope.applyToEvent(event, Hint()); expect(updatedEvent?.transaction, 'name'); }); @@ -573,7 +593,7 @@ void main() { sut.addEventProcessor(fixture.processor); final event = SentryEvent(); - var newEvent = await sut.applyToEvent(event); + var newEvent = await sut.applyToEvent(event, Hint()); expect(newEvent, isNull); }); @@ -582,7 +602,7 @@ void main() { var tr = SentryTransaction(fixture.sentryTracer); final scope = Scope(SentryOptions(dsn: fakeDsn))..fingerprint = ['test']; - final updatedTr = await scope.applyToEvent(tr); + final updatedTr = await scope.applyToEvent(tr, Hint()); expect(updatedTr?.fingerprint, isNull); }); @@ -591,7 +611,7 @@ void main() { var tr = SentryTransaction(fixture.sentryTracer); final scope = Scope(SentryOptions(dsn: fakeDsn))..level = SentryLevel.error; - final updatedTr = await scope.applyToEvent(tr); + final updatedTr = await scope.applyToEvent(tr, Hint()); expect(updatedTr?.level, isNull); }); @@ -600,7 +620,7 @@ void main() { var tr = SentryTransaction(fixture.sentryTracer); final scope = Scope(SentryOptions(dsn: fakeDsn))..level = SentryLevel.error; - final updatedTr = await scope.applyToEvent(tr); + final updatedTr = await scope.applyToEvent(tr, Hint()); expect(updatedTr?.contexts.trace?.sampled, isTrue); }); @@ -617,9 +637,9 @@ void main() { final sut = fixture.getSut( scopeObserver: fixture.mockScopeObserver, beforeBreadcrumbCallback: ( - Breadcrumb? breadcrumb, { - Hint? hint, - }) { + Breadcrumb? breadcrumb, + Hint hint, + ) { return breadcrumb?.copyWith(message: "modified"); }, ); @@ -690,9 +710,9 @@ void main() { final sut = fixture.getSut( beforeBreadcrumbCallback: ( - Breadcrumb? breadcrumb, { - Hint? hint, - }) { + Breadcrumb? breadcrumb, + Hint hint, + ) { throw exception; }, debug: true); @@ -714,9 +734,9 @@ void main() { final sut = fixture.getSut( beforeBreadcrumbCallback: ( - Breadcrumb? breadcrumb, { - Hint? hint, - }) { + Breadcrumb? breadcrumb, + Hint hint, + ) { if (numberOfBeforeBreadcrumbCalls > 0) { throw exception; } @@ -777,11 +797,11 @@ class Fixture { EventProcessor get processor => DropAllEventProcessor(); - Breadcrumb? beforeBreadcrumbCallback(Breadcrumb? breadcrumb, {Hint? hint}) => + Breadcrumb? beforeBreadcrumbCallback(Breadcrumb? breadcrumb, Hint hint) => null; - Breadcrumb? beforeBreadcrumbMutateCallback(Breadcrumb? breadcrumb, - {Hint? hint}) => + Breadcrumb? beforeBreadcrumbMutateCallback( + Breadcrumb? breadcrumb, Hint hint) => breadcrumb?.copyWith(message: 'new message'); void mockLogger( @@ -802,7 +822,7 @@ class AddTagsEventProcessor implements EventProcessor { AddTagsEventProcessor(this.tags); @override - SentryEvent? apply(SentryEvent event, {hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return event..tags?.addAll(tags); } } diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index 484dd009a5..522bfcae73 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -12,6 +12,7 @@ import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:sentry/src/transport/data_category.dart'; +import 'package:sentry/src/utils/iterable_utils.dart'; import 'package:test/test.dart'; import 'mocks.dart'; @@ -825,25 +826,14 @@ void main() { }); }); - group('SentryClient: apply default pii', () { + group('SentryClient: sets user & user ip', () { late Fixture fixture; setUp(() { fixture = Fixture(); }); - test('sendDefaultPii is disabled', () async { - final client = fixture.getSut(sendDefaultPii: false); - - await client.captureEvent(fakeEvent); - - final capturedEnvelope = fixture.transport.envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect(capturedEvent.user?.toJson(), fakeEvent.user?.toJson()); - }); - - test('sendDefaultPii is enabled and event has no user', () async { + test('event has no user', () async { final client = fixture.getSut(sendDefaultPii: true); var fakeEvent = SentryEvent(); @@ -857,7 +847,7 @@ void main() { expect(capturedEvent.user?.ipAddress, '{{auto}}'); }); - test('sendDefaultPii is enabled and event has a user with IP address', + test('event has a user with IP address', () async { final client = fixture.getSut(sendDefaultPii: true); @@ -874,7 +864,7 @@ void main() { expect(capturedEvent.user?.email, fakeEvent.user!.email); }); - test('sendDefaultPii is enabled and event has a user without IP address', + test('event has a user without IP address', () async { final client = fixture.getSut(sendDefaultPii: true); @@ -1038,7 +1028,7 @@ void main() { test('thrown error is handled', () async { final exception = Exception("before send exception"); - final beforeSendCallback = (SentryEvent event, {Hint? hint}) { + final beforeSendCallback = (SentryEvent event, Hint hint) { throw exception; }; @@ -1058,7 +1048,7 @@ void main() { setUp(() { fixture = Fixture(); fixture.options.addEventProcessor(FunctionEventProcessor( - (event, {hint}) => event + (event, hint) => event ..tags!.addAll({'theme': 'material'}) // ignore: deprecated_member_use_from_same_package ..extra!['host'] = '0.0.0.1' @@ -1100,8 +1090,8 @@ void main() { var executed = false; - final client = fixture.getSut( - eventProcessor: FunctionEventProcessor((event, {hint}) { + final client = + fixture.getSut(eventProcessor: FunctionEventProcessor((event, hint) { expect(myHint, hint); executed = true; return event; @@ -1115,8 +1105,8 @@ void main() { test('should create hint when none was provided', () async { var executed = false; - final client = fixture.getSut( - eventProcessor: FunctionEventProcessor((event, {hint}) { + final client = + fixture.getSut(eventProcessor: FunctionEventProcessor((event, hint) { expect(hint, isNotNull); executed = true; return event; @@ -1152,201 +1142,6 @@ void main() { }); }); - group('Breadcrumbs', () { - late Fixture fixture; - - setUp(() { - fixture = Fixture(); - }); - - test('Clears breadcrumbs on Android for transaction', () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final transaction = SentryTransaction( - fixture.tracer, - breadcrumbs: [ - Breadcrumb(), - ], - ); - await client.captureTransaction(transaction); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedTransaction = - await transactionFromEnvelope(capturedEnvelope); - - expect((capturedTransaction['breadcrumbs'] ?? []).isEmpty, true); - }); - - test('Clears breadcrumbs on Android if mechanism.handled is true for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: true, - ), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isEmpty, true); - }); - - test('Clears breadcrumbs on Android if mechanism.handled is null for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism(type: 'type'), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isEmpty, true); - }); - - test('Clears breadcrumbs on Android if theres no mechanism for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isEmpty, true); - }); - - test( - 'Does not clear breadcrumbs on Android if mechanism.handled is false for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: false, - ), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true); - }); - - test( - 'Does not clear breadcrumbs on Android if any mechanism.handled is false for event', - () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = - MockPlatformChecker(platform: MockPlatform.android()); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: true, - ), - ), - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: false, - ), - ) - ], breadcrumbs: [ - Breadcrumb() - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true); - }); - - test('web breadcrumbs exist on web Android devices', () async { - fixture.options.enableScopeSync = true; - fixture.options.platformChecker = MockPlatformChecker( - platform: MockPlatform.android(), - isWebValue: true, - ); - - final client = fixture.getSut(); - final event = SentryEvent(exceptions: [ - SentryException( - type: "type", - value: "value", - mechanism: Mechanism( - type: 'type', - handled: true, - ), - ), - ], breadcrumbs: [ - Breadcrumb(), - ]); - await client.captureEvent(event); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final capturedEvent = await eventFromEnvelope(capturedEnvelope); - - expect((capturedEvent.breadcrumbs ?? []).isNotEmpty, true); - }); - }); - group('ClientReportRecorder', () { late Fixture fixture; @@ -1426,8 +1221,10 @@ void main() { await sut.captureEvent(fakeEvent, hint: hint); final capturedEnvelope = (fixture.transport).envelopes.first; - final attachmentItem = capturedEnvelope.items.firstWhereOrNull( - (element) => element.header.type == SentryItemType.attachment); + final attachmentItem = IterableUtils.firstWhereOrNull( + capturedEnvelope.items, + (SentryEnvelopeItem e) => e.header.type == SentryItemType.attachment, + ); expect(attachmentItem?.header.attachmentType, SentryAttachment.typeAttachmentDefault); }); @@ -1598,9 +1395,9 @@ Future> transactionFromEnvelope( } SentryEvent? beforeSendCallbackDropEvent( - SentryEvent event, { - Hint? hint, -}) => + SentryEvent event, + Hint hint, +) => null; SentryTransaction? beforeSendTransactionCallbackDropEvent( @@ -1609,9 +1406,9 @@ SentryTransaction? beforeSendTransactionCallbackDropEvent( null; Future asyncBeforeSendCallbackDropEvent( - SentryEvent event, { - Hint? hint, -}) async { + SentryEvent event, + Hint hint, +) async { await Future.delayed(Duration(milliseconds: 200)); return null; } @@ -1622,7 +1419,7 @@ Future asyncBeforeSendTransactionCallbackDropEvent( return null; } -SentryEvent? beforeSendCallback(SentryEvent event, {Hint? hint}) { +SentryEvent? beforeSendCallback(SentryEvent event, Hint hint) { return event ..tags!.addAll({'theme': 'material'}) // ignore: deprecated_member_use_from_same_package @@ -1698,8 +1495,7 @@ class Fixture { return client; } - Future droppingBeforeSend(SentryEvent event, - {Hint? hint}) async { + Future droppingBeforeSend(SentryEvent event, Hint hint) async { return null; } diff --git a/dart/test/sentry_tracer_test.dart b/dart/test/sentry_tracer_test.dart index cb9f72fdfc..24649e23b2 100644 --- a/dart/test/sentry_tracer_test.dart +++ b/dart/test/sentry_tracer_test.dart @@ -68,24 +68,7 @@ void main() { expect(sut.endTimestamp, endTimestamp); }); - test( - 'tracer finish sets given end timestamp to all children while finishing them', - () async { - final sut = fixture.getSut(); - - final childA = sut.startChild('operation-a', description: 'description'); - final childB = sut.startChild('operation-b', description: 'description'); - final endTimestamp = getUtcDateTime(); - - await sut.finish(endTimestamp: endTimestamp); - await childA.finish(); - await childB.finish(); - - expect(childA.endTimestamp, endTimestamp); - expect(childB.endTimestamp, endTimestamp); - }); - - test('tracer finishes unfinished spans', () async { + test('tracer does not finish unfinished spans', () async { final sut = fixture.getSut(); sut.startChild('child'); @@ -94,7 +77,8 @@ void main() { final tr = fixture.hub.captureTransactionCalls.first; final child = tr.transaction.spans.first; - expect(child.status.toString(), 'deadline_exceeded'); + expect(child.status, isNull); + expect(child.endTimestamp, isNull); }); test('tracer sets data to extra', () async { diff --git a/dart/test/utils/http_sanitizer_test.dart b/dart/test/utils/http_sanitizer_test.dart index f9967c2778..2a4e0a58be 100644 --- a/dart/test/utils/http_sanitizer_test.dart +++ b/dart/test/utils/http_sanitizer_test.dart @@ -182,7 +182,7 @@ void main() { }); } -extension StringExtension on String { +extension _StringExtension on String { String _capitalize() { return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; } diff --git a/dio/lib/src/dio_event_processor.dart b/dio/lib/src/dio_event_processor.dart index 3a9603abd1..afeb692be4 100644 --- a/dio/lib/src/dio_event_processor.dart +++ b/dio/lib/src/dio_event_processor.dart @@ -15,7 +15,7 @@ class DioEventProcessor implements EventProcessor { final SentryOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/dio/lib/src/failed_request_interceptor.dart b/dio/lib/src/failed_request_interceptor.dart index 60ea4a0133..ecdd8ab2fa 100644 --- a/dio/lib/src/failed_request_interceptor.dart +++ b/dio/lib/src/failed_request_interceptor.dart @@ -27,7 +27,7 @@ class FailedRequestInterceptor extends Interceptor { final captureFailedRequests = _hub.options.captureFailedRequests; final containsStatusCode = - _failedRequestStatusCodes.containsStatusCode(err.response?.statusCode); + _failedRequestStatusCodes._containsStatusCode(err.response?.statusCode); final containsRequestTarget = containsTargetOrMatchesRegExp( _failedRequestTargets, err.requestOptions.path, @@ -46,7 +46,7 @@ class FailedRequestInterceptor extends Interceptor { } extension _ListX on List { - bool containsStatusCode(int? statusCode) { + bool _containsStatusCode(int? statusCode) { if (statusCode == null) { return false; } diff --git a/dio/test/dio_event_processor_test.dart b/dio/test/dio_event_processor_test.dart index af45d0c681..af4a94ab8d 100644 --- a/dio/test/dio_event_processor_test.dart +++ b/dio/test/dio_event_processor_test.dart @@ -24,7 +24,7 @@ void main() { throwable: Exception(), exceptions: [fixture.sentryError(throwable)], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(event, processedEvent); }); @@ -42,7 +42,7 @@ void main() { request: SentryRequest(), exceptions: [fixture.sentryError(dioError)], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(event.throwable, processedEvent.throwable); expect(event.request, processedEvent.request); @@ -67,10 +67,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.request?.method, 'POST'); @@ -96,10 +96,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.request?.method, 'GET'); @@ -125,10 +125,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.request?.headers, {}); }); @@ -177,10 +177,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; final capturedRequest = processedEvent.request; expect(capturedRequest, isNotNull); @@ -207,7 +207,7 @@ void main() { data: 'foobar', headers: Headers.fromMap(>{ 'foo': ['bar'], - 'set-cookie': ['foo=bar'] + 'set-cookie': ['foo=bar'], }), requestOptions: request, isRedirect: true, @@ -219,10 +219,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.contexts.response, isNotNull); @@ -248,7 +248,7 @@ void main() { response: Response( data: 'foobar', headers: Headers.fromMap(>{ - 'foo': ['bar'] + 'foo': ['bar'], }), requestOptions: request, isRedirect: true, @@ -260,10 +260,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.throwable, event.throwable); expect(processedEvent.contexts.response, isNotNull); @@ -320,10 +320,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; final capturedResponse = processedEvent.contexts.response; expect(capturedResponse, isNotNull); @@ -338,7 +338,7 @@ void main() { final dataByType = { ResponseType.plain: ['plain'], ResponseType.bytes: [ - [1337] + [1337], ], ResponseType.json: [ 9001, @@ -347,7 +347,7 @@ void main() { true, ['list'], {'map-key': 'map-value'}, - ] + ], }; for (final entry in dataByType.entries) { @@ -375,10 +375,10 @@ void main() { throwable: throwable, exceptions: [ fixture.sentryError(throwable), - fixture.sentryError(dioError) + fixture.sentryError(dioError), ], ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; final capturedResponse = processedEvent.contexts.response; expect(capturedResponse, isNotNull); @@ -413,7 +413,7 @@ void main() { exceptions: exceptions, ); - final processedEvent = sut.apply(event) as SentryEvent; + final processedEvent = sut.apply(event, Hint()) as SentryEvent; expect(processedEvent.exceptions?.length, 2); diff --git a/dio/test/failed_request_interceptor_test.dart b/dio/test/failed_request_interceptor_test.dart index 80eede8803..e7fb5a63e1 100644 --- a/dio/test/failed_request_interceptor_test.dart +++ b/dio/test/failed_request_interceptor_test.dart @@ -113,7 +113,7 @@ class Fixture { FailedRequestInterceptor getSut({ List failedRequestStatusCodes = const [ - SentryStatusCode.defaultRange() + SentryStatusCode.defaultRange(), ], List failedRequestTargets = const ['.*'], }) { diff --git a/dio/test/mocks.dart b/dio/test/mocks.dart index 83454cbfb3..30e53c5772 100644 --- a/dio/test/mocks.dart +++ b/dio/test/mocks.dart @@ -42,7 +42,7 @@ final fakeEvent = SentryEvent( type: 'navigation', data: {'screen': 'MainActivity', 'state': 'created'}, level: SentryLevel.info, - ) + ), ], contexts: Contexts( operatingSystem: const SentryOperatingSystem( @@ -98,7 +98,7 @@ final fakeEvent = SentryEvent( /// Doesn't do anything with the events class NoOpEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return event; } } @@ -106,7 +106,7 @@ class NoOpEventProcessor implements EventProcessor { /// Always returns null and thus drops all events class DropAllEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { return null; } } @@ -117,15 +117,15 @@ class FunctionEventProcessor implements EventProcessor { final EventProcessorFunction applyFunction; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { - return applyFunction(event, hint: hint); + SentryEvent? apply(SentryEvent event, Hint hint) { + return applyFunction(event, hint); } } typedef EventProcessorFunction = SentryEvent? Function( - SentryEvent event, { - Hint? hint, -}); + SentryEvent event, + Hint hint, +); var fakeEnvelope = SentryEnvelope.fromEvent( fakeEvent, diff --git a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt index cc864f7333..58423b91fa 100644 --- a/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt +++ b/flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutterPlugin.kt @@ -21,6 +21,7 @@ import io.sentry.SentryOptions import io.sentry.android.core.ActivityFramesTracker import io.sentry.android.core.AppStartState import io.sentry.android.core.BuildConfig.VERSION_NAME +import io.sentry.android.core.InternalSentrySdk import io.sentry.android.core.LoadClass import io.sentry.android.core.SentryAndroid import io.sentry.android.core.SentryAndroidOptions @@ -65,6 +66,7 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { "removeExtra" -> removeExtra(call.argument("key"), result) "setTag" -> setTag(call.argument("key"), call.argument("value"), result) "removeTag" -> removeTag(call.argument("key"), result) + "loadContexts" -> loadContexts(result) else -> result.notImplemented() } } @@ -94,18 +96,6 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { // Stub } - private fun writeEnvelope(envelope: ByteArray): Boolean { - val options = HubAdapter.getInstance().options - if (options.outboxPath.isNullOrEmpty()) { - return false - } - - val file = File(options.outboxPath, UUID.randomUUID().toString()) - file.writeBytes(envelope) - - return true - } - private fun initNativeSdk(call: MethodCall, result: Result) { if (!this::context.isInitialized) { result.error("1", "Context is null", null) @@ -356,20 +346,19 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { result.error("1", "The Sentry Android SDK is disabled", null) return } - - val args = call.arguments() as List? ?: listOf() + val args = call.arguments() as List? ?: listOf() if (args.isNotEmpty()) { val event = args.first() as ByteArray? - if (event != null && event.isNotEmpty()) { - if (!writeEnvelope(event)) { - result.error("2", "SentryOptions or outboxPath are null or empty", null) + val id = InternalSentrySdk.captureEnvelope(event) + if (id != null) { + result.success("") + } else { + result.error("2", "Failed to capture envelope", null) } - result.success("") return } } - result.error("3", "Envelope is null or empty", null) } @@ -454,6 +443,21 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { } } } + + private fun loadContexts(result: Result) { + val options = HubAdapter.getInstance().options + if (options !is SentryAndroidOptions) { + result.success(null) + return + } + val currentScope = InternalSentrySdk.getCurrentScope() + val serializedScope = InternalSentrySdk.serializeScope( + context, + options, + currentScope + ) + result.success(serializedScope) + } } // Call the `completion` closure if cast to map value with `key` and type `T` is successful. diff --git a/flutter/example/integration_test/integration_test.dart b/flutter/example/integration_test/integration_test.dart index ae42ae3945..9dc182111a 100644 --- a/flutter/example/integration_test/integration_test.dart +++ b/flutter/example/integration_test/integration_test.dart @@ -199,7 +199,7 @@ void main() { class Fixture { SentryEvent? sentEvent; - FutureOr beforeSend(SentryEvent event, {Hint? hint}) async { + FutureOr beforeSend(SentryEvent event, Hint hint) async { sentEvent = event; return event; } diff --git a/flutter/example/ios/Podfile b/flutter/example/ios/Podfile index 313ea4a153..2c068c404b 100644 --- a/flutter/example/ios/Podfile +++ b/flutter/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/flutter/ios/sentry_flutter.podspec b/flutter/ios/sentry_flutter.podspec index 0b0351bd44..687410d5fe 100644 --- a/flutter/ios/sentry_flutter.podspec +++ b/flutter/ios/sentry_flutter.podspec @@ -15,7 +15,7 @@ Sentry SDK for Flutter with support to native through sentry-cocoa. s.dependency 'Sentry/HybridSDK', '8.10.0' s.ios.dependency 'Flutter' s.osx.dependency 'FlutterMacOS' - s.ios.deployment_target = '11.0' + s.ios.deployment_target = '12.0' # Flutter 3.7 requires 10.14 s.osx.deployment_target = '10.13' diff --git a/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart b/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart index 377af31d25..ce77150c40 100644 --- a/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart +++ b/flutter/lib/src/event_processor/android_platform_exception_event_processor.dart @@ -19,7 +19,7 @@ class AndroidPlatformExceptionEventProcessor implements EventProcessor { static final _platformExceptionType = (PlatformException).toString(); @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { if (event is SentryTransaction) { return event; } diff --git a/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart b/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart index f72eb2470b..0df522c379 100644 --- a/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart +++ b/flutter/lib/src/event_processor/flutter_enricher_event_processor.dart @@ -31,9 +31,9 @@ class FlutterEnricherEventProcessor implements EventProcessor { @override Future apply( - SentryEvent event, { - Hint? hint, - }) async { + SentryEvent event, + Hint hint, + ) async { // If there's a native integration available, it probably has better // information available than Flutter. final device = diff --git a/flutter/lib/src/event_processor/flutter_exception_event_processor.dart b/flutter/lib/src/event_processor/flutter_exception_event_processor.dart index e0f4b6af14..05f9fd6595 100644 --- a/flutter/lib/src/event_processor/flutter_exception_event_processor.dart +++ b/flutter/lib/src/event_processor/flutter_exception_event_processor.dart @@ -3,7 +3,7 @@ import 'package:sentry/sentry.dart'; class FlutterExceptionEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/flutter/lib/src/event_processor/native_app_start_event_processor.dart b/flutter/lib/src/event_processor/native_app_start_event_processor.dart index 2187204299..0127f36d5a 100644 --- a/flutter/lib/src/event_processor/native_app_start_event_processor.dart +++ b/flutter/lib/src/event_processor/native_app_start_event_processor.dart @@ -18,7 +18,7 @@ class NativeAppStartEventProcessor implements EventProcessor { final SentryNative _native; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { final appStartEnd = _native.appStartEnd; if (appStartEnd != null && diff --git a/flutter/lib/src/event_processor/platform_exception_event_processor.dart b/flutter/lib/src/event_processor/platform_exception_event_processor.dart index d403509ae9..2bf33e60f9 100644 --- a/flutter/lib/src/event_processor/platform_exception_event_processor.dart +++ b/flutter/lib/src/event_processor/platform_exception_event_processor.dart @@ -4,7 +4,7 @@ import 'package:sentry/sentry.dart'; /// Add code & message from [PlatformException] to [SentryException] class PlatformExceptionEventProcessor implements EventProcessor { @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } diff --git a/flutter/lib/src/event_processor/screenshot_event_processor.dart b/flutter/lib/src/event_processor/screenshot_event_processor.dart index b60f4faefa..8a68fed1c1 100644 --- a/flutter/lib/src/event_processor/screenshot_event_processor.dart +++ b/flutter/lib/src/event_processor/screenshot_event_processor.dart @@ -19,7 +19,7 @@ class ScreenshotEventProcessor implements EventProcessor { sentryScreenshotWidgetGlobalKey.currentContext != null; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { if (event is SentryTransaction) { return event; } @@ -40,7 +40,7 @@ class ScreenshotEventProcessor implements EventProcessor { final bytes = await _createScreenshot(); if (bytes != null) { - hint?.screenshot = SentryAttachment.fromScreenshotData(bytes); + hint.screenshot = SentryAttachment.fromScreenshotData(bytes); } return event; } diff --git a/flutter/lib/src/integrations/flutter_error_integration.dart b/flutter/lib/src/integrations/flutter_error_integration.dart index a9f10bcc09..03f8436bf9 100644 --- a/flutter/lib/src/integrations/flutter_error_integration.dart +++ b/flutter/lib/src/integrations/flutter_error_integration.dart @@ -54,11 +54,8 @@ class FlutterErrorIntegration implements Integration { stackTrace: errorDetails.stack, ); - // FlutterError doesn't crash the App. - final mechanism = Mechanism( - type: 'FlutterError', - handled: true, - ); + // FlutterError doesn't crash the app, but is not handled by the user. + final mechanism = Mechanism(type: 'FlutterError', handled: false); final throwableMechanism = ThrowableMechanism(mechanism, exception); var event = SentryEvent( diff --git a/flutter/lib/src/integrations/load_contexts_integration.dart b/flutter/lib/src/integrations/load_contexts_integration.dart index 710d7d0924..6395e134cf 100644 --- a/flutter/lib/src/integrations/load_contexts_integration.dart +++ b/flutter/lib/src/integrations/load_contexts_integration.dart @@ -4,21 +4,16 @@ import 'package:flutter/services.dart'; import 'package:sentry/sentry.dart'; import '../sentry_flutter_options.dart'; -/// Load Device's Contexts from the iOS SDK. +/// Load Device's Contexts from the iOS & Android SDKs. /// -/// This integration calls the iOS SDK via Message channel to load the -/// Device's contexts before sending the event back to the iOS SDK via +/// This integration calls the iOS & Android SDKs via Message channel to load +/// the Device's contexts before sending the event back to the SDK via /// Message channel (already enriched with all the information). /// /// The Device's contexts are: /// App, Device and OS. /// -/// ps. This integration won't be run on Android because the Device's Contexts -/// is set on Android when the event is sent to the Android SDK via -/// the Message channel. -/// We intend to unify this behaviour in the future. -/// -/// This integration is only executed on iOS & MacOS Apps. +/// This integration is only executed on iOS, macOS & Android Apps. class LoadContextsIntegration extends Integration { final MethodChannel _channel; @@ -40,7 +35,7 @@ class _LoadContextsIntegrationEventProcessor implements EventProcessor { final SentryFlutterOptions _options; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { try { final loadContexts = await _channel.invokeMethod('loadContexts'); @@ -194,8 +189,8 @@ class _LoadContextsIntegrationEventProcessor implements EventProcessor { event = event.copyWith(sdk: sdk); } - // on iOS, captureEnvelope does not call the beforeSend callback, - // hence we need to add these tags here. + // captureEnvelope does not call the beforeSend callback, hence we need to + // add these tags here. if (event.sdk?.name == 'sentry.dart.flutter') { final tags = event.tags ?? {}; tags['event.origin'] = 'flutter'; diff --git a/flutter/lib/src/integrations/load_image_list_integration.dart b/flutter/lib/src/integrations/load_image_list_integration.dart index c2a0c98848..a06d60d839 100644 --- a/flutter/lib/src/integrations/load_image_list_integration.dart +++ b/flutter/lib/src/integrations/load_image_list_integration.dart @@ -43,7 +43,7 @@ class _LoadImageListIntegrationEventProcessor implements EventProcessor { final SentryFlutterOptions _options; @override - Future apply(SentryEvent event, {Hint? hint}) async { + Future apply(SentryEvent event, Hint hint) async { if (event.needsSymbolication()) { try { // we call on every event because the loaded image list is cached diff --git a/flutter/lib/src/sentry_flutter.dart b/flutter/lib/src/sentry_flutter.dart index 13aa7cc552..860990b213 100644 --- a/flutter/lib/src/sentry_flutter.dart +++ b/flutter/lib/src/sentry_flutter.dart @@ -154,7 +154,7 @@ mixin SentryFlutter { // Will enrich events with device context, native packages and integrations if (platformChecker.hasNativeIntegration && !platformChecker.isWeb && - (platform.isIOS || platform.isMacOS)) { + (platform.isIOS || platform.isMacOS || platform.isAndroid)) { integrations.add(LoadContextsIntegration(channel)); } diff --git a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart index f98a919065..46b25e5cb3 100644 --- a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart +++ b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart @@ -313,7 +313,8 @@ class _SentryUserInteractionWidgetState void _onTappedAt(Offset position) { final tappedWidget = _getElementAt(position); - final keyValue = tappedWidget?.element.widget.key?.toStringValue(); + final keyValue = + WidgetUtils.toStringValue(tappedWidget?.element.widget.key); if (tappedWidget == null || keyValue == null) { return; } diff --git a/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart b/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart index 2a85bf49be..41b03f4808 100644 --- a/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart +++ b/flutter/lib/src/view_hierarchy/sentry_tree_walker.dart @@ -281,7 +281,7 @@ class _TreeWalker { return SentryViewHierarchyElement( element.widget.runtimeType.toString(), depth: element.depth, - identifier: element.widget.key?.toStringValue(), + identifier: WidgetUtils.toStringValue(element.widget.key), width: width, height: height, x: x, diff --git a/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart b/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart index 99d43ad982..c3fefe52f5 100644 --- a/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart +++ b/flutter/lib/src/view_hierarchy/view_hierarchy_event_processor.dart @@ -1,7 +1,7 @@ import '../../sentry_flutter.dart'; import 'sentry_tree_walker.dart'; -/// A [EventProcessor] that renders an ASCII represention of the entire view +/// A [EventProcessor] that renders an ASCII representation of the entire view /// hierarchy of the application when an error happens and includes it as an /// attachment to the [Hint]. class SentryViewHierarchyEventProcessor implements EventProcessor { @@ -10,7 +10,7 @@ class SentryViewHierarchyEventProcessor implements EventProcessor { final SentryFlutterOptions _options; @override - SentryEvent? apply(SentryEvent event, {Hint? hint}) { + SentryEvent? apply(SentryEvent event, Hint hint) { if (event is SentryTransaction) { return event; } @@ -31,7 +31,7 @@ class SentryViewHierarchyEventProcessor implements EventProcessor { final viewHierarchy = SentryAttachment.fromViewHierarchy(sentryViewHierarchy); - hint?.viewHierarchy = viewHierarchy; + hint.viewHierarchy = viewHierarchy; return event; } } diff --git a/flutter/lib/src/widget_utils.dart b/flutter/lib/src/widget_utils.dart index 9d63b8d5a3..97d51a990a 100644 --- a/flutter/lib/src/widget_utils.dart +++ b/flutter/lib/src/widget_utils.dart @@ -1,8 +1,12 @@ import 'package:flutter/widgets.dart'; +import 'package:meta/meta.dart'; -extension WidgetExtension on Key { - String? toStringValue() { - final key = this; +@internal +class WidgetUtils { + static String? toStringValue(Key? key) { + if (key == null) { + return null; + } if (key is ValueKey) { return key.value; } else if (key is ValueKey) { diff --git a/flutter/test/android_platform_exception_event_processor_test.dart b/flutter/test/android_platform_exception_event_processor_test.dart index bfd8e2b4ce..0ac142922a 100644 --- a/flutter/test/android_platform_exception_event_processor_test.dart +++ b/flutter/test/android_platform_exception_event_processor_test.dart @@ -26,8 +26,8 @@ void main() { group(AndroidPlatformExceptionEventProcessor, () { test('exception is correctly parsed', () async { - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 2); @@ -45,8 +45,8 @@ void main() { test( 'Dart thread is current and not crashed if Android exception is present', () async { - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 2); @@ -56,8 +56,8 @@ void main() { }); test('platformexception has Android thread attached', () async { - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 2); @@ -76,8 +76,8 @@ void main() { fixture.options.attachThreads = false; final threadCount = fixture.eventWithPlatformStackTrace.threads?.length; - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithPlatformStackTrace, Hint()); final exceptions = platformExceptionEvent!.exceptions!; expect(exceptions.length, 2); @@ -94,14 +94,15 @@ void main() { throwable: null, ); - final platformExceptionEvent = await fixture.processor.apply(event); + final platformExceptionEvent = + await fixture.processor.apply(event, Hint()); expect(event, platformExceptionEvent); }); test('does nothing if PlatformException has no stackTrace', () async { - final platformExceptionEvent = - await fixture.processor.apply(fixture.eventWithoutPlatformStackTrace); + final platformExceptionEvent = await fixture.processor + .apply(fixture.eventWithoutPlatformStackTrace, Hint()); expect(fixture.eventWithoutPlatformStackTrace, platformExceptionEvent); }); diff --git a/flutter/test/event_processor/flutter_enricher_event_processor_test.dart b/flutter/test/event_processor/flutter_enricher_event_processor_test.dart index bfccb8c773..72ff0fc1cb 100644 --- a/flutter/test/event_processor/flutter_enricher_event_processor_test.dart +++ b/flutter/test/event_processor/flutter_enricher_event_processor_test.dart @@ -32,7 +32,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); debugBrightnessOverride = null; debugDefaultTargetPlatformOverride = null; @@ -48,7 +48,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final accessibility = event?.contexts['accessibility']; @@ -65,7 +65,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final culture = event?.contexts.culture; @@ -79,7 +79,7 @@ void main() { ); tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final app = event?.contexts.app; @@ -92,7 +92,7 @@ void main() { ); tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.inactive); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final app = event?.contexts.app; @@ -110,7 +110,7 @@ void main() { final event = SentryEvent(); event.contexts.app = SentryApp(name: appName); - final mutatedEvent = await enricher.apply(event); + final mutatedEvent = await enricher.apply(event, Hint()); final app = mutatedEvent?.contexts.app; @@ -125,7 +125,7 @@ void main() { hasNativeIntegration: true, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNull); }); @@ -137,7 +137,7 @@ void main() { hasNativeIntegration: false, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.contexts.device, isNotNull); }); @@ -147,7 +147,7 @@ void main() { binding: () => tester.binding, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final flutterRuntime = event?.contexts.runtimes .firstWhere((element) => element.name == 'Flutter'); @@ -171,7 +171,7 @@ void main() { checker: pair.key, ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); final flutterRuntime = event?.contexts.runtimes .firstWhere((element) => element.name == 'Flutter'); @@ -199,7 +199,7 @@ void main() { ), ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.modules, { 'foo_package': 'unknown', @@ -227,7 +227,7 @@ void main() { ), ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.modules, null); }); @@ -251,7 +251,7 @@ void main() { ), ); - final event = await enricher.apply(SentryEvent()); + final event = await enricher.apply(SentryEvent(), Hint()); expect(event?.modules, {'foo_package': 'unknown'}); }); @@ -276,7 +276,7 @@ void main() { hasNativeIntegration: false, ); - final event = await enricher.apply(fakeEvent); + final event = await enricher.apply(fakeEvent, Hint()); // contexts.device expect( diff --git a/flutter/test/event_processor/flutter_exception_event_processor_test.dart b/flutter/test/event_processor/flutter_exception_event_processor_test.dart index aaca15e2af..8dc4f5c528 100644 --- a/flutter/test/event_processor/flutter_exception_event_processor_test.dart +++ b/flutter/test/event_processor/flutter_exception_event_processor_test.dart @@ -20,6 +20,7 @@ void main() { uri: Uri.parse('https://example.org/foo/bar?foo=bar'), ), ), + Hint(), ); expect(event?.request, isNotNull); diff --git a/flutter/test/event_processor/platform_exception_event_processor_test.dart b/flutter/test/event_processor/platform_exception_event_processor_test.dart index d4bf2d9c99..ecc3d7130b 100644 --- a/flutter/test/event_processor/platform_exception_event_processor_test.dart +++ b/flutter/test/event_processor/platform_exception_event_processor_test.dart @@ -26,7 +26,7 @@ void main() { var event = SentryEvent(exceptions: [sentryException]); final sut = fixture.getSut(); - event = (sut.apply(event))!; + event = (sut.apply(event, Hint()))!; expect(event.exceptions?.first.mechanism?.data["code"], "fixture-code"); expect(event.exceptions?.first.mechanism?.data["message"], @@ -46,7 +46,7 @@ void main() { var event = SentryEvent(exceptions: [sentryException]); final sut = fixture.getSut(); - event = (sut.apply(event))!; + event = (sut.apply(event, Hint()))!; expect(event.exceptions?.first.mechanism?.type, "platformException"); }); diff --git a/flutter/test/event_processor/screenshot_event_processor_test.dart b/flutter/test/event_processor/screenshot_event_processor_test.dart index da063e776c..6101217a04 100644 --- a/flutter/test/event_processor/screenshot_event_processor_test.dart +++ b/flutter/test/event_processor/screenshot_event_processor_test.dart @@ -32,7 +32,7 @@ void main() { final throwable = Exception(); final event = SentryEvent(throwable: throwable); final hint = Hint(); - await sut.apply(event, hint: hint); + await sut.apply(event, hint); expect(hint.screenshot != null, added); if (expectedMaxWidthOrHeight != null) { diff --git a/flutter/test/integrations/flutter_error_integration_test.dart b/flutter/test/integrations/flutter_error_integration_test.dart index 53446caeda..43df8de278 100644 --- a/flutter/test/integrations/flutter_error_integration_test.dart +++ b/flutter/test/integrations/flutter_error_integration_test.dart @@ -70,7 +70,7 @@ void main() { final throwableMechanism = event.throwableMechanism as ThrowableMechanism; expect(throwableMechanism.mechanism.type, 'FlutterError'); - expect(throwableMechanism.mechanism.handled, true); + expect(throwableMechanism.mechanism.handled, false); expect(throwableMechanism.throwable, exception); expect(event.contexts['flutter_error_details']['library'], 'sentry'); @@ -102,7 +102,7 @@ void main() { final throwableMechanism = event.throwableMechanism as ThrowableMechanism; expect(throwableMechanism.mechanism.type, 'FlutterError'); - expect(throwableMechanism.mechanism.handled, true); + expect(throwableMechanism.mechanism.handled, false); expect(event.contexts['flutter_error_details']['library'], 'sentry'); expect(event.contexts['flutter_error_details']['context'], @@ -126,7 +126,7 @@ void main() { final throwableMechanism = event.throwableMechanism as ThrowableMechanism; expect(throwableMechanism.mechanism.type, 'FlutterError'); - expect(throwableMechanism.mechanism.handled, true); + expect(throwableMechanism.mechanism.handled, false); expect(throwableMechanism.mechanism.data['hint'], isNull); expect(event.contexts['flutter_error_details'], isNull); diff --git a/flutter/test/integrations/load_contexts_integration_test.dart b/flutter/test/integrations/load_contexts_integration_test.dart index a97b35db77..bf93f6da46 100644 --- a/flutter/test/integrations/load_contexts_integration_test.dart +++ b/flutter/test/integrations/load_contexts_integration_test.dart @@ -58,7 +58,8 @@ void main() { final integration = LoadContextsIntegration(fixture.methodChannel); integration.call(fixture.hub, fixture.options); - event = (await fixture.options.eventProcessors.first.apply(event))!; + event = + (await fixture.options.eventProcessors.first.apply(event, Hint()))!; expect(event.breadcrumbs!.length, 1); expect(event.breadcrumbs!.first.message, 'native'); @@ -83,7 +84,8 @@ void main() { final integration = LoadContextsIntegration(fixture.methodChannel); integration.call(fixture.hub, fixture.options); - event = (await fixture.options.eventProcessors.first.apply(event))!; + event = + (await fixture.options.eventProcessors.first.apply(event, Hint()))!; expect(event.breadcrumbs!.length, 1); expect(event.breadcrumbs!.first.message, 'event'); diff --git a/flutter/test/integrations/load_contexts_integrations_test.dart b/flutter/test/integrations/load_contexts_integrations_test.dart index c6bb98f0b7..6de2d32e8d 100644 --- a/flutter/test/integrations/load_contexts_integrations_test.dart +++ b/flutter/test/integrations/load_contexts_integrations_test.dart @@ -81,7 +81,7 @@ void main() { e.contexts.operatingSystem = SentryOperatingSystem(theme: 'theme1'); e.contexts.app = SentryApp(inForeground: true); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(fixture.called, true); expect(event?.contexts.device?.name, 'Device1'); @@ -121,7 +121,7 @@ void main() { final e = SentryEvent(contexts: eventContexts, user: SentryUser(id: 'myId')); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(fixture.called, true); expect(event?.contexts.device?.name, 'eDevice'); @@ -145,7 +145,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.packages.any((element) => element.name == 'native-package'), @@ -169,7 +170,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.integrations @@ -189,7 +191,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.packages @@ -210,7 +213,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect( event?.sdk?.packages @@ -239,7 +243,7 @@ void main() { integration(fixture.hub, fixture.options); final e = SentryEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event, isNotNull); }); @@ -252,7 +256,8 @@ void main() { final eventSdk = getSdkVersion(name: 'sentry.dart.flutter'); final e = getEvent(sdk: eventSdk); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?['event.origin'], 'flutter'); expect(event?.tags?['event.environment'], 'dart'); @@ -270,7 +275,8 @@ void main() { sdk: eventSdk, tags: {'a': 'b'}, ); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?['event.origin'], 'flutter'); expect(event?.tags?['event.environment'], 'dart'); @@ -285,7 +291,8 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(tags: {}); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = + await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?.containsKey('event.origin'), false); expect(event?.tags?.containsKey('event.environment'), false); @@ -298,7 +305,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(tags: {'key': 'flutter', 'key-a': 'flutter'}); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.tags?['key'], 'flutter'); expect(event?.tags?['key-a'], 'flutter'); @@ -311,7 +318,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(extra: {'key': 'flutter', 'key-a': 'flutter'}); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); // ignore: deprecated_member_use expect(event?.extra?['key'], 'flutter'); @@ -326,7 +333,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.user?.id, '196E065A-AAF7-409A-9A6C-A81F40274CB9'); expect(event?.user?.username, 'fixture-username'); @@ -340,7 +347,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(user: SentryUser(id: 'abc')); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.user?.id, 'abc'); }); @@ -350,7 +357,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.dist, 'fixture-dist'); }); @@ -360,7 +367,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(dist: 'abc'); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.dist, 'abc'); }); @@ -370,7 +377,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.environment, 'fixture-environment'); }); @@ -380,7 +387,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(environment: 'abc'); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.environment, 'abc'); }); @@ -391,7 +398,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(fingerprint: ['fingerprint-a', 'fingerprint-b']); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.fingerprint, ['fingerprint-a', 'fingerprint-b']); }); @@ -401,7 +408,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.level, SentryLevel.error); }); @@ -411,7 +418,7 @@ void main() { integration(fixture.hub, fixture.options); final e = getEvent(level: SentryLevel.fatal); - final event = await fixture.options.eventProcessors.first.apply(e); + final event = await fixture.options.eventProcessors.first.apply(e, Hint()); expect(event?.level, SentryLevel.fatal); }); diff --git a/flutter/test/integrations/load_image_list_test.dart b/flutter/test/integrations/load_image_list_test.dart index bb78561dae..1b82a3332e 100644 --- a/flutter/test/integrations/load_image_list_test.dart +++ b/flutter/test/integrations/load_image_list_test.dart @@ -135,7 +135,7 @@ void main() { final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); expect(1, event!.debugMeta!.images.length); }); @@ -146,7 +146,7 @@ void main() { sut.call(fixture.hub, fixture.options); final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); final image = event!.debugMeta!.images.first; diff --git a/flutter/test/integrations/native_app_start_integration_test.dart b/flutter/test/integrations/native_app_start_integration_test.dart index b2ef832705..467ac9bb55 100644 --- a/flutter/test/integrations/native_app_start_integration_test.dart +++ b/flutter/test/integrations/native_app_start_integration_test.dart @@ -32,7 +32,8 @@ void main() { final transaction = SentryTransaction(tracer); final processor = fixture.options.eventProcessors.first; - final enriched = await processor.apply(transaction) as SentryTransaction; + final enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; final measurement = enriched.measurements['app_start_cold']!; expect(measurement.value, 10); @@ -52,8 +53,10 @@ void main() { final processor = fixture.options.eventProcessors.first; - var enriched = await processor.apply(transaction) as SentryTransaction; - var secondEnriched = await processor.apply(enriched) as SentryTransaction; + var enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + var secondEnriched = + await processor.apply(enriched, Hint()) as SentryTransaction; expect(secondEnriched.measurements.length, 1); }); @@ -72,8 +75,10 @@ void main() { final processor = fixture.options.eventProcessors.first; - var enriched = await processor.apply(transaction) as SentryTransaction; - var secondEnriched = await processor.apply(enriched) as SentryTransaction; + var enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; + var secondEnriched = + await processor.apply(enriched, Hint()) as SentryTransaction; expect(secondEnriched.measurements.length, 2); expect(secondEnriched.measurements.containsKey(measurement.name), true); @@ -90,7 +95,8 @@ void main() { final transaction = SentryTransaction(tracer); final processor = fixture.options.eventProcessors.first; - final enriched = await processor.apply(transaction) as SentryTransaction; + final enriched = + await processor.apply(transaction, Hint()) as SentryTransaction; expect(enriched.measurements.isEmpty, true); }); diff --git a/flutter/test/load_image_list_test.dart b/flutter/test/load_image_list_test.dart index 0afff01b97..345d913887 100644 --- a/flutter/test/load_image_list_test.dart +++ b/flutter/test/load_image_list_test.dart @@ -127,7 +127,7 @@ void main() { final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); expect(1, event!.debugMeta!.images.length); }); @@ -138,7 +138,7 @@ void main() { sut.call(fixture.hub, fixture.options); final ep = fixture.options.eventProcessors.first; SentryEvent? event = _getEvent(); - event = await ep.apply(event); + event = await ep.apply(event, Hint()); final image = event!.debugMeta!.images.first; diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index 56f6f250a6..9a7df7d063 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -27,9 +27,10 @@ final nonWebIntegrations = [ OnErrorIntegration, ]; -// These should only be added to Android +// These should be added to Android final androidIntegrations = [ LoadImageListIntegration, + LoadContextsIntegration, ]; // These should be added to iOS and macOS diff --git a/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart b/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart index 537b2cd9c4..a409d1a293 100644 --- a/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart +++ b/flutter/test/view_hierarchy/view_hierarchy_event_processor_test.dart @@ -26,7 +26,7 @@ void main() { exceptions: [SentryException(type: 'type', value: 'value')]); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNotNull); }); @@ -42,7 +42,7 @@ void main() { final event = SentryEvent(throwable: StateError('error')); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNotNull); }); @@ -58,7 +58,7 @@ void main() { final event = SentryEvent(); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNull); }); @@ -74,7 +74,7 @@ void main() { final event = SentryEvent(); final hint = Hint(); - sut.apply(event, hint: hint); + sut.apply(event, hint); expect(hint.viewHierarchy, isNull); }); diff --git a/min_version_test/ios/Podfile b/min_version_test/ios/Podfile index 88359b225f..2c068c404b 100644 --- a/min_version_test/ios/Podfile +++ b/min_version_test/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/sqflite/test/mocks/mocks.dart b/sqflite/test/mocks/mocks.dart index 0a3115df74..bcafb94302 100644 --- a/sqflite/test/mocks/mocks.dart +++ b/sqflite/test/mocks/mocks.dart @@ -33,7 +33,9 @@ ISentrySpan startTransactionShim( DatabaseExecutor, ], customMocks: [ - MockSpec(fallbackGenerators: {#startTransaction: startTransactionShim}) + MockSpec( + fallbackGenerators: {#startTransaction: startTransactionShim}, + ), ], ) void main() {}