From 957cde249bbc2c83c83f3c752043d663b82dd304 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 15 Nov 2022 14:15:45 +0100 Subject: [PATCH 01/38] introduce hint class --- dart/lib/sentry.dart | 1 + .../enricher/io_enricher_event_processor.dart | 3 ++- .../web_enricher_event_processor.dart | 3 ++- dart/lib/src/event_processor.dart | 3 ++- dart/lib/src/hint.dart | 21 +++++++++++++++++++ dart/lib/src/hub.dart | 9 ++++---- dart/lib/src/hub_adapter.dart | 9 ++++---- dart/lib/src/noop_hub.dart | 9 ++++---- dart/lib/src/noop_sentry_client.dart | 7 ++++--- dart/lib/src/scope.dart | 7 ++++--- dart/lib/src/sentry.dart | 9 ++++---- dart/lib/src/sentry_client.dart | 9 ++++---- dart/lib/src/sentry_options.dart | 5 +++-- dart/test/default_integrations_test.dart | 3 ++- dart/test/mocks.dart | 3 ++- dart/test/mocks/mock_hub.dart | 17 ++++++++------- dart/test/mocks/mock_sentry_client.dart | 13 ++++++------ dart/test/scope_test.dart | 10 ++++----- dart/test/sentry_client_test.dart | 15 +++++++------ dio/lib/src/dio_event_processor.dart | 2 +- dio/test/mocks.dart | 8 +++---- dio/test/mocks/mock_hub.dart | 16 +++++++------- ...id_platform_exception_event_processor.dart | 2 +- .../src/flutter_enricher_event_processor.dart | 2 +- flutter/test/mocks.mocks.dart | 11 +++++----- logging/test/mock_hub.dart | 4 ++-- 26 files changed, 120 insertions(+), 81 deletions(-) create mode 100644 dart/lib/src/hint.dart diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index 717434c8f9..9fff649dab 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -30,3 +30,4 @@ export 'src/sentry_user_feedback.dart'; export 'src/utils/tracing_utils.dart'; // tracing export 'src/tracing.dart'; +export 'src/hint.dart'; diff --git a/dart/lib/src/enricher/io_enricher_event_processor.dart b/dart/lib/src/enricher/io_enricher_event_processor.dart index 005047b777..ea4801b613 100644 --- a/dart/lib/src/enricher/io_enricher_event_processor.dart +++ b/dart/lib/src/enricher/io_enricher_event_processor.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:io'; import '../event_processor.dart'; +import '../hint.dart'; import '../protocol.dart'; import '../sentry_options.dart'; @@ -20,7 +21,7 @@ class IoEnricherEventProcessor extends EventProcessor { final SentryOptions _options; @override - FutureOr apply(SentryEvent event, {dynamic hint}) { + FutureOr 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/enricher/web_enricher_event_processor.dart b/dart/lib/src/enricher/web_enricher_event_processor.dart index 594867dc06..be57ebcf06 100644 --- a/dart/lib/src/enricher/web_enricher_event_processor.dart +++ b/dart/lib/src/enricher/web_enricher_event_processor.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:html' as html show window, Window; import '../event_processor.dart'; +import '../hint.dart'; import '../protocol.dart'; import '../sentry_options.dart'; @@ -23,7 +24,7 @@ class WebEnricherEventProcessor extends EventProcessor { final SentryOptions _options; @override - FutureOr apply(SentryEvent event, {dynamic hint}) { + FutureOr 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.dart b/dart/lib/src/event_processor.dart index 8c09db2050..94fcd77fd8 100644 --- a/dart/lib/src/event_processor.dart +++ b/dart/lib/src/event_processor.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'hint.dart'; import 'protocol.dart'; /// [EventProcessor]s are callbacks that run for every event. They can either @@ -8,6 +9,6 @@ import 'protocol.dart'; abstract class EventProcessor { FutureOr apply( SentryEvent event, { - dynamic hint, + Hint? hint, }); } diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart new file mode 100644 index 0000000000..1bb0ccc2d3 --- /dev/null +++ b/dart/lib/src/hint.dart @@ -0,0 +1,21 @@ +import 'sentry_attachment/sentry_attachment.dart'; + +class Hint { + // Objects + + void set(String key, Object? value) {} + + Object? get(String key) { + return null; + } + + Object? remove(String key) { + return null; + } + + bool contains(String key) { + return false; + } + + void clear() {} +} diff --git a/dart/lib/src/hub.dart b/dart/lib/src/hub.dart index 784432984d..0413f2f0f1 100644 --- a/dart/lib/src/hub.dart +++ b/dart/lib/src/hub.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:collection'; import 'package:meta/meta.dart'; +import 'hint.dart'; import 'transport/data_category.dart'; import '../sentry.dart'; @@ -69,7 +70,7 @@ class Hub { Future captureEvent( SentryEvent event, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { var sentryId = SentryId.empty(); @@ -112,7 +113,7 @@ class Hub { Future captureException( dynamic throwable, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { var sentryId = SentryId.empty(); @@ -168,7 +169,7 @@ class Hub { SentryLevel? level, String? template, List? params, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { var sentryId = SentryId.empty(); @@ -258,7 +259,7 @@ class Hub { } /// Adds a breacrumb to the current Scope - Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async { + Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async { if (!_isEnabled) { _options.logger( SentryLevel.warning, diff --git a/dart/lib/src/hub_adapter.dart b/dart/lib/src/hub_adapter.dart index 5dd32dbfe8..b7a0813a23 100644 --- a/dart/lib/src/hub_adapter.dart +++ b/dart/lib/src/hub_adapter.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:meta/meta.dart'; +import 'hint.dart'; import 'hub.dart'; import 'protocol.dart'; @@ -25,7 +26,7 @@ class HubAdapter implements Hub { } @override - Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async => + Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async => await Sentry.addBreadcrumb(crumb, hint: hint); @override @@ -35,7 +36,7 @@ class HubAdapter implements Hub { Future captureEvent( SentryEvent event, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) => Sentry.captureEvent( @@ -49,7 +50,7 @@ class HubAdapter implements Hub { Future captureException( dynamic throwable, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) => Sentry.captureException( @@ -65,7 +66,7 @@ class HubAdapter implements Hub { SentryLevel? level, String? template, List? params, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) => Sentry.captureMessage( diff --git a/dart/lib/src/noop_hub.dart b/dart/lib/src/noop_hub.dart index 6dded21914..ea005184b6 100644 --- a/dart/lib/src/noop_hub.dart +++ b/dart/lib/src/noop_hub.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:meta/meta.dart'; +import 'hint.dart'; import 'hub.dart'; import 'protocol.dart'; import 'sentry_client.dart'; @@ -31,7 +32,7 @@ class NoOpHub implements Hub { Future captureEvent( SentryEvent event, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async => SentryId.empty(); @@ -40,7 +41,7 @@ class NoOpHub implements Hub { Future captureException( dynamic throwable, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async => SentryId.empty(); @@ -51,7 +52,7 @@ class NoOpHub implements Hub { SentryLevel? level, String? template, List? params, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async => SentryId.empty(); @@ -72,7 +73,7 @@ class NoOpHub implements Hub { SentryId get lastEventId => SentryId.empty(); @override - Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async {} + Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async {} @override Future captureTransaction( diff --git a/dart/lib/src/noop_sentry_client.dart b/dart/lib/src/noop_sentry_client.dart index 0e953118f6..593d63f74b 100644 --- a/dart/lib/src/noop_sentry_client.dart +++ b/dart/lib/src/noop_sentry_client.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'hint.dart'; import 'protocol.dart'; import 'scope.dart'; import 'sentry_client.dart'; @@ -21,7 +22,7 @@ class NoOpSentryClient implements SentryClient { SentryEvent event, { dynamic stackTrace, Scope? scope, - dynamic hint, + Hint? hint, }) async => SentryId.empty(); @@ -30,7 +31,7 @@ class NoOpSentryClient implements SentryClient { dynamic exception, { dynamic stackTrace, Scope? scope, - dynamic hint, + Hint? hint, }) async => SentryId.empty(); @@ -41,7 +42,7 @@ class NoOpSentryClient implements SentryClient { String? template, List? params, Scope? scope, - dynamic hint, + Hint? hint, }) async => SentryId.empty(); diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart index 5e63a0a8ec..b24b572087 100644 --- a/dart/lib/src/scope.dart +++ b/dart/lib/src/scope.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:collection'; import 'event_processor.dart'; +import 'hint.dart'; import 'protocol.dart'; import 'scope_observer.dart'; import 'sentry_attachment/sentry_attachment.dart'; @@ -165,7 +166,7 @@ class Scope { Scope(this._options); - bool _addBreadCrumbSync(Breadcrumb breadcrumb, {dynamic hint}) { + bool _addBreadCrumbSync(Breadcrumb breadcrumb, {Hint? hint}) { // bail out if maxBreadcrumbs is zero if (_options.maxBreadcrumbs == 0) { return false; @@ -207,7 +208,7 @@ class Scope { } /// Adds a breadcrumb to the breadcrumbs queue - Future addBreadcrumb(Breadcrumb breadcrumb, {dynamic hint}) async { + Future addBreadcrumb(Breadcrumb breadcrumb, {Hint? hint}) async { if (_addBreadCrumbSync(breadcrumb, hint: hint)) { await _callScopeObservers((scopeObserver) async => await scopeObserver.addBreadcrumb(breadcrumb)); @@ -294,7 +295,7 @@ class Scope { Future applyToEvent( SentryEvent event, { - dynamic hint, + Hint? hint, }) async { event = event.copyWith( transaction: event.transaction ?? _transaction, diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index e2733711e3..15c298b1e2 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -6,6 +6,7 @@ import 'default_integrations.dart'; import 'enricher/enricher_event_processor.dart'; import 'environment/environment_variables.dart'; import 'event_processor/deduplication_event_processor.dart'; +import 'hint.dart'; import 'hub.dart'; import 'hub_adapter.dart'; import 'integration.dart'; @@ -144,7 +145,7 @@ class Sentry { static Future captureEvent( SentryEvent event, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) => _hub.captureEvent( @@ -158,7 +159,7 @@ class Sentry { static Future captureException( dynamic throwable, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) => _hub.captureException( @@ -173,7 +174,7 @@ class Sentry { SentryLevel? level = SentryLevel.info, String? template, List? params, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) => _hub.captureMessage( @@ -202,7 +203,7 @@ class Sentry { static SentryId get lastEventId => _hub.lastEventId; /// Adds a breacrumb to the current Scope - static Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async => + static Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async => await _hub.addBreadcrumb(crumb, hint: hint); /// Configures the scope through the callback. diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index b250badf7e..359c2ad2eb 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:meta/meta.dart'; import 'event_processor.dart'; +import 'hint.dart'; import 'sentry_trace_context_header.dart'; import 'sentry_user_feedback.dart'; import 'transport/rate_limiter.dart'; @@ -58,7 +59,7 @@ class SentryClient { SentryEvent event, { Scope? scope, dynamic stackTrace, - dynamic hint, + Hint? hint, }) async { if (_sampleRate()) { _recordLostEvent(event, DiscardReason.sampleRate); @@ -247,7 +248,7 @@ class SentryClient { dynamic throwable, { dynamic stackTrace, Scope? scope, - dynamic hint, + Hint? hint, }) { final event = SentryEvent( throwable: throwable, @@ -269,7 +270,7 @@ class SentryClient { String? template, List? params, Scope? scope, - dynamic hint, + Hint? hint, }) { final event = SentryEvent( message: SentryMessage(formatted, template: template, params: params), @@ -344,7 +345,7 @@ class SentryClient { Future _processEvent( SentryEvent event, { - dynamic hint, + Hint? hint, required List eventProcessors, }) async { SentryEvent? processedEvent = event; diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 361486e1d6..32e8ec02b3 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -7,6 +7,7 @@ import 'package:http/http.dart'; import '../sentry.dart'; import 'client_reports/client_report_recorder.dart'; import 'client_reports/noop_client_report_recorder.dart'; +import 'hint.dart'; import 'sentry_exception_factory.dart'; import 'sentry_stack_trace_factory.dart'; import 'diagnostic_logger.dart'; @@ -380,14 +381,14 @@ class SentryOptions { /// object or nothing to skip reporting the event typedef BeforeSendCallback = FutureOr Function( SentryEvent event, { - dynamic hint, + Hint? hint, }); /// 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, { - dynamic hint, + Hint? hint, }); /// Used to provide timestamp for logging. diff --git a/dart/test/default_integrations_test.dart b/dart/test/default_integrations_test.dart index 7881768113..e7adfcbdfb 100644 --- a/dart/test/default_integrations_test.dart +++ b/dart/test/default_integrations_test.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; +import 'package:sentry/src/hint.dart'; import 'package:test/test.dart'; import 'mocks.dart'; @@ -225,7 +226,7 @@ class PrintRecursionMockHub extends MockHub { bool get isEnabled => true; @override - Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async { + Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async { print('recursion'); await super.addBreadcrumb(crumb, hint: hint); } diff --git a/dart/test/mocks.dart b/dart/test/mocks.dart index b03d515969..9d06dffbc2 100644 --- a/dart/test/mocks.dart +++ b/dart/test/mocks.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; +import 'package:sentry/src/hint.dart'; import 'package:sentry/src/transport/rate_limiter.dart'; final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; @@ -124,7 +125,7 @@ class FunctionEventProcessor extends EventProcessor { } typedef EventProcessorFunction = FutureOr - Function(SentryEvent event, {dynamic hint}); + Function(SentryEvent event, {Hint? hint}); var fakeEnvelope = SentryEnvelope.fromEvent( fakeEvent, SdkVersion(name: 'sdk1', version: '1.0.0')); diff --git a/dart/test/mocks/mock_hub.dart b/dart/test/mocks/mock_hub.dart index 46f98800ab..1411ef52e4 100644 --- a/dart/test/mocks/mock_hub.dart +++ b/dart/test/mocks/mock_hub.dart @@ -1,5 +1,6 @@ import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; +import 'package:sentry/src/hint.dart'; import '../mocks.dart'; import 'mock_sentry_client.dart'; @@ -39,7 +40,7 @@ class MockHub with NoSuchMethodProvider implements Hub { } @override - Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async { + Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async { addBreadcrumbCalls.add(AddBreadcrumbCall(crumb, hint)); } @@ -52,7 +53,7 @@ class MockHub with NoSuchMethodProvider implements Hub { Future captureEvent( SentryEvent event, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { captureEventCalls.add(CaptureEventCall( @@ -67,7 +68,7 @@ class MockHub with NoSuchMethodProvider implements Hub { Future captureException( dynamic throwable, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { captureExceptionCalls.add(CaptureExceptionCall( @@ -84,7 +85,7 @@ class MockHub with NoSuchMethodProvider implements Hub { SentryLevel? level = SentryLevel.info, String? template, List? params, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { captureMessageCalls.add(CaptureMessageCall( @@ -136,7 +137,7 @@ class MockHub with NoSuchMethodProvider implements Hub { class CaptureEventCall { final SentryEvent event; final dynamic stackTrace; - final dynamic hint; + final Hint? hint; CaptureEventCall(this.event, this.stackTrace, this.hint); } @@ -144,7 +145,7 @@ class CaptureEventCall { class CaptureExceptionCall { final dynamic throwable; final dynamic stackTrace; - final dynamic hint; + final Hint? hint; CaptureExceptionCall( this.throwable, @@ -158,7 +159,7 @@ class CaptureMessageCall { final SentryLevel? level; final String? template; final List? params; - final dynamic hint; + final Hint? hint; CaptureMessageCall( this.message, @@ -171,7 +172,7 @@ class CaptureMessageCall { class AddBreadcrumbCall { final Breadcrumb crumb; - final dynamic hint; + final Hint? hint; AddBreadcrumbCall(this.crumb, this.hint); } diff --git a/dart/test/mocks/mock_sentry_client.dart b/dart/test/mocks/mock_sentry_client.dart index 419a075d2d..565bfbf524 100644 --- a/dart/test/mocks/mock_sentry_client.dart +++ b/dart/test/mocks/mock_sentry_client.dart @@ -1,4 +1,5 @@ import 'package:sentry/sentry.dart'; +import 'package:sentry/src/hint.dart'; import 'no_such_method_provider.dart'; @@ -16,7 +17,7 @@ class MockSentryClient with NoSuchMethodProvider implements SentryClient { SentryEvent event, { Scope? scope, dynamic stackTrace, - dynamic hint, + Hint? hint, }) async { captureEventCalls.add(CaptureEventCall( event, @@ -32,7 +33,7 @@ class MockSentryClient with NoSuchMethodProvider implements SentryClient { dynamic throwable, { dynamic stackTrace, Scope? scope, - dynamic hint, + Hint? hint, }) async { captureExceptionCalls.add(CaptureExceptionCall( throwable, @@ -50,7 +51,7 @@ class MockSentryClient with NoSuchMethodProvider implements SentryClient { String? template, List? params, Scope? scope, - dynamic hint, + Hint? hint, }) async { captureMessageCalls.add(CaptureMessageCall( formatted, @@ -95,7 +96,7 @@ class CaptureEventCall { final SentryEvent event; final Scope? scope; final dynamic stackTrace; - final dynamic hint; + final Hint? hint; CaptureEventCall( this.event, @@ -109,7 +110,7 @@ class CaptureExceptionCall { final dynamic throwable; final dynamic stackTrace; final Scope? scope; - final dynamic hint; + final Hint? hint; CaptureExceptionCall( this.throwable, @@ -125,7 +126,7 @@ class CaptureMessageCall { final String? template; final List? params; final Scope? scope; - final dynamic hint; + final Hint? hint; CaptureMessageCall( this.formatted, diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart index de3d2f7d55..e4efcf51e2 100644 --- a/dart/test/scope_test.dart +++ b/dart/test/scope_test.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; +import 'package:sentry/src/hint.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; @@ -650,7 +651,7 @@ void main() { final sut = fixture.getSut( beforeBreadcrumbCallback: ( Breadcrumb? breadcrumb, { - dynamic hint, + Hint? hint, }) { throw exception; }, @@ -674,7 +675,7 @@ void main() { final sut = fixture.getSut( beforeBreadcrumbCallback: ( Breadcrumb? breadcrumb, { - dynamic hint, + Hint? hint, }) { if (numberOfBeforeBreadcrumbCalls > 0) { throw exception; @@ -732,12 +733,11 @@ class Fixture { EventProcessor get processor => DropAllEventProcessor(); - Breadcrumb? beforeBreadcrumbCallback(Breadcrumb? breadcrumb, - {dynamic hint}) => + Breadcrumb? beforeBreadcrumbCallback(Breadcrumb? breadcrumb, {Hint? hint}) => null; Breadcrumb? beforeBreadcrumbMutateCallback(Breadcrumb? breadcrumb, - {dynamic hint}) => + {Hint? hint}) => breadcrumb?.copyWith(message: 'new message'); void mockLogger( diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index 5161fcb53b..e27a2d8020 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -7,6 +7,7 @@ import 'package:sentry/src/client_reports/client_report.dart'; import 'package:sentry/src/client_reports/discard_reason.dart'; import 'package:sentry/src/client_reports/discarded_event.dart'; import 'package:sentry/src/client_reports/noop_client_report_recorder.dart'; +import 'package:sentry/src/hint.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:sentry/src/sentry_tracer.dart'; @@ -784,7 +785,7 @@ void main() { test('thrown error is handled', () async { final exception = Exception("before send exception"); - final beforeSendCallback = (SentryEvent event, {dynamic hint}) { + final beforeSendCallback = (SentryEvent event, {Hint? hint}) { throw exception; }; @@ -839,7 +840,9 @@ void main() { }); test('should pass hint to eventProcessors', () async { - final myHint = 'hint'; + final myHint = Hint(); + myHint.set('string', 'hint'); + var executed = false; final client = fixture.getSut( @@ -1217,19 +1220,19 @@ Future> transactionFromEnvelope( FutureOr beforeSendCallbackDropEvent( SentryEvent event, { - dynamic hint, + Hint? hint, }) => null; FutureOr asyncBeforeSendCallbackDropEvent( SentryEvent event, { - dynamic hint, + Hint? hint, }) async { await Future.delayed(Duration(milliseconds: 200)); return null; } -FutureOr beforeSendCallback(SentryEvent event, {dynamic hint}) { +FutureOr beforeSendCallback(SentryEvent event, {Hint? hint}) { return event ..tags!.addAll({'theme': 'material'}) ..extra!['host'] = '0.0.0.1' @@ -1292,7 +1295,7 @@ class Fixture { } FutureOr droppingBeforeSend(SentryEvent event, - {dynamic hint}) async { + {Hint? hint}) async { return null; } diff --git a/dio/lib/src/dio_event_processor.dart b/dio/lib/src/dio_event_processor.dart index 08db23702c..da8e3822b0 100644 --- a/dio/lib/src/dio_event_processor.dart +++ b/dio/lib/src/dio_event_processor.dart @@ -22,7 +22,7 @@ class DioEventProcessor implements EventProcessor { _options.exceptionFactory; @override - FutureOr apply(SentryEvent event, {dynamic hint}) { + FutureOr apply(SentryEvent event, {Hint? hint}) { final dynamic dioError = event.throwable; if (dioError is! DioError) { return event; diff --git a/dio/test/mocks.dart b/dio/test/mocks.dart index 6ca13675c5..c7b73427e1 100644 --- a/dio/test/mocks.dart +++ b/dio/test/mocks.dart @@ -99,7 +99,7 @@ final fakeEvent = SentryEvent( /// Doesn't do anything with the events class NoOpEventProcessor extends EventProcessor { @override - FutureOr apply(SentryEvent event, {dynamic hint}) { + FutureOr apply(SentryEvent event, {Hint? hint}) { return event; } } @@ -107,7 +107,7 @@ class NoOpEventProcessor extends EventProcessor { /// Always returns null and thus drops all events class DropAllEventProcessor extends EventProcessor { @override - FutureOr apply(SentryEvent event, {dynamic hint}) { + FutureOr apply(SentryEvent event, {Hint? hint}) { return null; } } @@ -118,13 +118,13 @@ class FunctionEventProcessor extends EventProcessor { final EventProcessorFunction applyFunction; @override - FutureOr apply(SentryEvent event, {dynamic hint}) { + FutureOr apply(SentryEvent event, {Hint? hint}) { return applyFunction(event, hint: hint); } } typedef EventProcessorFunction = FutureOr - Function(SentryEvent event, {dynamic hint}); + Function(SentryEvent event, {Hint? hint}); var fakeEnvelope = SentryEnvelope.fromEvent( fakeEvent, diff --git a/dio/test/mocks/mock_hub.dart b/dio/test/mocks/mock_hub.dart index c7eef58c2b..377e1efb79 100644 --- a/dio/test/mocks/mock_hub.dart +++ b/dio/test/mocks/mock_hub.dart @@ -38,7 +38,7 @@ class MockHub with NoSuchMethodProvider implements Hub { } @override - Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async { + Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async { addBreadcrumbCalls.add(AddBreadcrumbCall(crumb, hint)); } @@ -51,7 +51,7 @@ class MockHub with NoSuchMethodProvider implements Hub { Future captureEvent( SentryEvent event, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { captureEventCalls.add( @@ -68,7 +68,7 @@ class MockHub with NoSuchMethodProvider implements Hub { Future captureException( dynamic throwable, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { captureExceptionCalls.add( @@ -87,7 +87,7 @@ class MockHub with NoSuchMethodProvider implements Hub { SentryLevel? level = SentryLevel.info, String? template, List? params, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { captureMessageCalls.add( @@ -140,7 +140,7 @@ class MockHub with NoSuchMethodProvider implements Hub { class CaptureEventCall { final SentryEvent event; final dynamic stackTrace; - final dynamic hint; + final Hint? hint; CaptureEventCall(this.event, this.stackTrace, this.hint); } @@ -148,7 +148,7 @@ class CaptureEventCall { class CaptureExceptionCall { final dynamic throwable; final dynamic stackTrace; - final dynamic hint; + final Hint? hint; CaptureExceptionCall( this.throwable, @@ -162,7 +162,7 @@ class CaptureMessageCall { final SentryLevel? level; final String? template; final List? params; - final dynamic hint; + final Hint? hint; CaptureMessageCall( this.message, @@ -175,7 +175,7 @@ class CaptureMessageCall { class AddBreadcrumbCall { final Breadcrumb crumb; - final dynamic hint; + final Hint? hint; AddBreadcrumbCall(this.crumb, this.hint); } 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 6707be3631..88d616ee07 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 - FutureOr apply(SentryEvent event, {dynamic hint}) async { + FutureOr apply(SentryEvent event, {Hint? hint}) async { final plaformException = event.throwable; if (plaformException is! PlatformException) { return event; diff --git a/flutter/lib/src/flutter_enricher_event_processor.dart b/flutter/lib/src/flutter_enricher_event_processor.dart index d72b0190fb..fa5b772168 100644 --- a/flutter/lib/src/flutter_enricher_event_processor.dart +++ b/flutter/lib/src/flutter_enricher_event_processor.dart @@ -44,7 +44,7 @@ class FlutterEnricherEventProcessor extends EventProcessor { @override FutureOr apply( SentryEvent event, { - dynamic hint, + Hint? hint, }) async { // If there's a native integration available, it probably has better // information available than Flutter. diff --git a/flutter/test/mocks.mocks.dart b/flutter/test/mocks.mocks.dart index 9bce2502a0..f1546ad460 100644 --- a/flutter/test/mocks.mocks.dart +++ b/flutter/test/mocks.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.3.1 from annotations +// Mocks generated by Mockito 5.3.2 from annotations // in sentry_flutter/example/windows/flutter/ephemeral/.plugin_symlinks/sentry_flutter/example/linux/flutter/ephemeral/.plugin_symlinks/sentry_flutter/example/ios/.symlinks/plugins/sentry_flutter/test/mocks.dart. // Do not manually edit this file. @@ -28,7 +28,6 @@ import 'mocks.dart' as _i12; // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class -// ignore_for_file: invalid_use_of_internal_member class _FakeSentrySpanContext_0 extends _i1.SmartFake implements _i2.SentrySpanContext { @@ -682,7 +681,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { _i6.Future<_i3.SentryId> captureEvent( _i3.SentryEvent? event, { dynamic stackTrace, - dynamic hint, + _i2.Hint? hint, _i2.ScopeCallback? withScope, }) => (super.noSuchMethod( @@ -712,7 +711,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { _i6.Future<_i3.SentryId> captureException( dynamic throwable, { dynamic stackTrace, - dynamic hint, + _i2.Hint? hint, _i2.ScopeCallback? withScope, }) => (super.noSuchMethod( @@ -744,7 +743,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { _i3.SentryLevel? level, String? template, List? params, - dynamic hint, + _i2.Hint? hint, _i2.ScopeCallback? withScope, }) => (super.noSuchMethod( @@ -787,7 +786,7 @@ class MockHub extends _i1.Mock implements _i2.Hub { @override _i6.Future addBreadcrumb( _i3.Breadcrumb? crumb, { - dynamic hint, + _i2.Hint? hint, }) => (super.noSuchMethod( Invocation.method( diff --git a/logging/test/mock_hub.dart b/logging/test/mock_hub.dart index 9abe5418e3..30049452d2 100644 --- a/logging/test/mock_hub.dart +++ b/logging/test/mock_hub.dart @@ -16,7 +16,7 @@ class MockHub with NoSuchMethodProvider implements Hub { SentryOptions get options => _options; @override - Future addBreadcrumb(Breadcrumb crumb, {dynamic hint}) async { + Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async { breadcrumbs.add(crumb); } @@ -24,7 +24,7 @@ class MockHub with NoSuchMethodProvider implements Hub { Future captureEvent( SentryEvent event, { dynamic stackTrace, - dynamic hint, + Hint? hint, ScopeCallback? withScope, }) async { events.add(CapturedEvents(event, stackTrace)); From 0c54fba98f3a0cd0d807d0db5692d5557d05862e Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 15 Nov 2022 14:52:18 +0100 Subject: [PATCH 02/38] implement hint internal storage --- dart/lib/src/hint.dart | 16 ++++++----- dart/test/hint_test.dart | 58 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 dart/test/hint_test.dart diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 1bb0ccc2d3..76c681284c 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,21 +1,23 @@ import 'sentry_attachment/sentry_attachment.dart'; class Hint { + Map internalStorage = {}; + // Objects - void set(String key, Object? value) {} + void set(String key, Object value) { + internalStorage[key] = value; + } Object? get(String key) { - return null; + return internalStorage[key]; } Object? remove(String key) { - return null; + return internalStorage.remove(key); } - bool contains(String key) { - return false; + void clear() { + internalStorage.clear(); } - - void clear() {} } diff --git a/dart/test/hint_test.dart b/dart/test/hint_test.dart new file mode 100644 index 0000000000..8f39dcdec2 --- /dev/null +++ b/dart/test/hint_test.dart @@ -0,0 +1,58 @@ +import 'package:sentry/src/hint.dart'; +import 'package:test/test.dart'; + +void main() { + test('Hint set value is returned with get', () { + final hint = Hint(); + hint.set("hint1", "some string"); + + expect("some string", hint.get("hint1")); + }); + + test('Hint get returns null if not contained', () { + final hint = Hint(); + expect(hint.get("hint-does-not-exist"), null); + }); + + test('Hint set multiple times only keeps latest value', () { + final hint = Hint(); + + hint.set("hint1", "some string"); + hint.set("hint1", "a different string"); + + expect("a different string", hint.get("hint1")); + }); + + test('Hint removed value is not returned by get', () { + final hint = Hint(); + + hint.set("hint1", "some string"); + expect("some string", hint.get("hint1")); + + hint.remove("hint1"); + expect(hint.get("hint1"), null); + }); + + test('Hint remove leaves other values', () { + final hint = Hint(); + + hint.set("hint1", "some string"); + expect("some string", hint.get("hint1")); + hint.set("hint2", "another string"); + + hint.remove("hint1"); + expect(hint.get("hint1"), null); + expect("another string", hint.get("hint2")); + }); + + test('Hint clear removes all values', () { + final hint = Hint(); + + hint.set("hint1", "some string"); + hint.set("hint2", "another string"); + + hint.clear(); + expect(hint.get("hint1"), null); + expect(hint.get("hint2"), null); + }); +} From f3b3e647e6aade83210a21a615e1e356c4b2bd18 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 15 Nov 2022 14:52:45 +0100 Subject: [PATCH 03/38] ignore --- flutter/test/mocks.mocks.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter/test/mocks.mocks.dart b/flutter/test/mocks.mocks.dart index f1546ad460..d31b2d6908 100644 --- a/flutter/test/mocks.mocks.dart +++ b/flutter/test/mocks.mocks.dart @@ -144,6 +144,7 @@ class MockTransport extends _i1.Mock implements _i2.Transport { /// A class which mocks [SentryTracer]. /// /// See the documentation for Mockito's code generation for more information. +// ignore: invalid_use_of_internal_member class MockSentryTracer extends _i1.Mock implements _i8.SentryTracer { MockSentryTracer() { _i1.throwOnMissingStub(this); From c863c7dbc03530c9a007599597b847fbb873af24 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 15 Nov 2022 14:55:05 +0100 Subject: [PATCH 04/38] remove unneccessary imports --- dart/lib/src/hint.dart | 2 -- dart/lib/src/hub.dart | 1 - dart/lib/src/sentry_options.dart | 1 - dart/test/default_integrations_test.dart | 1 - dart/test/mocks.dart | 1 - dart/test/mocks/mock_hub.dart | 1 - dart/test/mocks/mock_sentry_client.dart | 1 - dart/test/scope_test.dart | 1 - dart/test/sentry_client_test.dart | 1 - 9 files changed, 10 deletions(-) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 76c681284c..e4250b2fd7 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,5 +1,3 @@ -import 'sentry_attachment/sentry_attachment.dart'; - class Hint { Map internalStorage = {}; diff --git a/dart/lib/src/hub.dart b/dart/lib/src/hub.dart index 0413f2f0f1..9ec51d924a 100644 --- a/dart/lib/src/hub.dart +++ b/dart/lib/src/hub.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:collection'; import 'package:meta/meta.dart'; -import 'hint.dart'; import 'transport/data_category.dart'; import '../sentry.dart'; diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 32e8ec02b3..2671673cbb 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -7,7 +7,6 @@ import 'package:http/http.dart'; import '../sentry.dart'; import 'client_reports/client_report_recorder.dart'; import 'client_reports/noop_client_report_recorder.dart'; -import 'hint.dart'; import 'sentry_exception_factory.dart'; import 'sentry_stack_trace_factory.dart'; import 'diagnostic_logger.dart'; diff --git a/dart/test/default_integrations_test.dart b/dart/test/default_integrations_test.dart index e7adfcbdfb..7af7618076 100644 --- a/dart/test/default_integrations_test.dart +++ b/dart/test/default_integrations_test.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; -import 'package:sentry/src/hint.dart'; import 'package:test/test.dart'; import 'mocks.dart'; diff --git a/dart/test/mocks.dart b/dart/test/mocks.dart index 9d06dffbc2..9570198fc2 100644 --- a/dart/test/mocks.dart +++ b/dart/test/mocks.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; -import 'package:sentry/src/hint.dart'; import 'package:sentry/src/transport/rate_limiter.dart'; final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; diff --git a/dart/test/mocks/mock_hub.dart b/dart/test/mocks/mock_hub.dart index 1411ef52e4..d8b4d7384b 100644 --- a/dart/test/mocks/mock_hub.dart +++ b/dart/test/mocks/mock_hub.dart @@ -1,6 +1,5 @@ import 'package:meta/meta.dart'; import 'package:sentry/sentry.dart'; -import 'package:sentry/src/hint.dart'; import '../mocks.dart'; import 'mock_sentry_client.dart'; diff --git a/dart/test/mocks/mock_sentry_client.dart b/dart/test/mocks/mock_sentry_client.dart index 565bfbf524..7b08250193 100644 --- a/dart/test/mocks/mock_sentry_client.dart +++ b/dart/test/mocks/mock_sentry_client.dart @@ -1,5 +1,4 @@ import 'package:sentry/sentry.dart'; -import 'package:sentry/src/hint.dart'; import 'no_such_method_provider.dart'; diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart index e4efcf51e2..d715309436 100644 --- a/dart/test/scope_test.dart +++ b/dart/test/scope_test.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:sentry/sentry.dart'; -import 'package:sentry/src/hint.dart'; import 'package:sentry/src/sentry_tracer.dart'; import 'package:test/test.dart'; diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index e27a2d8020..5be2952298 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -7,7 +7,6 @@ import 'package:sentry/src/client_reports/client_report.dart'; import 'package:sentry/src/client_reports/discard_reason.dart'; import 'package:sentry/src/client_reports/discarded_event.dart'; import 'package:sentry/src/client_reports/noop_client_report_recorder.dart'; -import 'package:sentry/src/hint.dart'; import 'package:sentry/src/sentry_item_type.dart'; import 'package:sentry/src/sentry_stack_trace_factory.dart'; import 'package:sentry/src/sentry_tracer.dart'; From fc5c48f0470f65c3f06c144f46795360b4e7ea36 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 15 Nov 2022 15:10:27 +0100 Subject: [PATCH 05/38] add changelog entry --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59e2a436e4..17a82b6d15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## 7.0.0 +### Features + +- Feat: Introduce Hint data bag ([#1136](https://github.com/getsentry/sentry-dart/pull/1136)) + +### Fixes + - Fix: Remove `SentryOptions` related parameters from classes which also take `Hub` as a parameter (#816) ### Breaking Changes From 6133acd9407be6bf536465022c0cda44c8e50741 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 15 Nov 2022 15:11:15 +0100 Subject: [PATCH 06/38] =?UTF-8?q?make=20=5FinternalStorage=20=E2=80=A6=20i?= =?UTF-8?q?nternal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dart/lib/src/hint.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index e4250b2fd7..7cb64e0f55 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,21 +1,21 @@ class Hint { - Map internalStorage = {}; + Map _internalStorage = {}; // Objects void set(String key, Object value) { - internalStorage[key] = value; + _internalStorage[key] = value; } Object? get(String key) { - return internalStorage[key]; + return _internalStorage[key]; } Object? remove(String key) { - return internalStorage.remove(key); + return _internalStorage.remove(key); } void clear() { - internalStorage.clear(); + _internalStorage.clear(); } } From 50a5b3e8f128f5f18dee1d64333105c79c2ecbbc Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 15 Nov 2022 15:11:36 +0100 Subject: [PATCH 07/38] =?UTF-8?q?=E2=80=A6=20and=20final?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dart/lib/src/hint.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 7cb64e0f55..2854e77016 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,5 +1,5 @@ class Hint { - Map _internalStorage = {}; + final Map _internalStorage = {}; // Objects From 07ecfb315357096f7438debac9bfeb19e1f0453e Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 10:10:05 +0100 Subject: [PATCH 08/38] =?UTF-8?q?don=E2=80=99t=20return=20obj=20on=20remov?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dart/lib/src/hint.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 2854e77016..5d470e68fb 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -11,8 +11,8 @@ class Hint { return _internalStorage[key]; } - Object? remove(String key) { - return _internalStorage.remove(key); + void remove(String key) { + _internalStorage.remove(key); } void clear() { From 1505bccb767c0257928ba6c24b49b94e0d88147b Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 10:24:06 +0100 Subject: [PATCH 09/38] create hint when none was provided --- dart/lib/src/sentry_client.dart | 4 ++++ dart/test/sentry_client_test.dart | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 359c2ad2eb..12e358cc29 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -72,6 +72,10 @@ class SentryClient { SentryEvent? preparedEvent = _prepareEvent(event, stackTrace: stackTrace); + if (hint == null) { + hint = Hint(); + } + if (scope != null) { preparedEvent = await scope.applyToEvent(preparedEvent, hint: hint); } else { diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index 5be2952298..d934cb8b89 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -856,6 +856,21 @@ void main() { expect(executed, true); }); + test('should create hint when none was provided', () async { + var executed = false; + + final client = fixture.getSut( + eventProcessor: FunctionEventProcessor((event, {hint}) { + expect(hint, isNotNull); + executed = true; + return event; + })); + + await client.captureEvent(fakeEvent); + + expect(executed, true); + }); + test('event processor drops the event', () async { final client = fixture.getSut(eventProcessor: DropAllEventProcessor()); await client.captureEvent(fakeEvent); From d97805f1f4fba3480cdb13e85e9036de3955ea78 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 10:26:14 +0100 Subject: [PATCH 10/38] synt. sugar --- dart/lib/src/sentry_client.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 12e358cc29..e5fa12251a 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -72,9 +72,7 @@ class SentryClient { SentryEvent? preparedEvent = _prepareEvent(event, stackTrace: stackTrace); - if (hint == null) { - hint = Hint(); - } + hint ??= Hint(); if (scope != null) { preparedEvent = await scope.applyToEvent(preparedEvent, hint: hint); From 63430fa3c626ea2cdbc43ec4cd6c1455fd8b08eb Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 11:11:30 +0100 Subject: [PATCH 11/38] pass log record as hint --- dart/lib/src/hint.dart | 6 ++++++ dart/test/hint_test.dart | 5 +++++ logging/lib/src/logging_integration.dart | 1 + logging/test/logging_integration_test.dart | 24 ++++++++++++++++++++++ logging/test/mock_hub.dart | 4 ++++ 5 files changed, 40 insertions(+) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 5d470e68fb..7994187383 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,6 +1,12 @@ class Hint { final Map _internalStorage = {}; + Hint(); + + Hint.fromMap(Map map) { + _internalStorage.addAll(map); + } + // Objects void set(String key, Object value) { diff --git a/dart/test/hint_test.dart b/dart/test/hint_test.dart index 8f39dcdec2..7176c21020 100644 --- a/dart/test/hint_test.dart +++ b/dart/test/hint_test.dart @@ -2,6 +2,11 @@ import 'package:sentry/src/hint.dart'; import 'package:test/test.dart'; void main() { + test('Hint init from map', () { + final hint = Hint.fromMap({'fixture-key': 'fixture-value'}); + expect("fixture-value", hint.get("fixture-key")); + }); + test('Hint set value is returned with get', () { final hint = Hint(); hint.set("hint1", "some string"); diff --git a/logging/lib/src/logging_integration.dart b/logging/lib/src/logging_integration.dart index 5ef935c77f..05a801ba0e 100644 --- a/logging/lib/src/logging_integration.dart +++ b/logging/lib/src/logging_integration.dart @@ -58,6 +58,7 @@ class LoggingIntegration extends Integration { await _hub.captureEvent( record.toEvent(), stackTrace: record.stackTrace, + hint: Hint.fromMap({'record': record}), ); } diff --git a/logging/test/logging_integration_test.dart b/logging/test/logging_integration_test.dart index fe73dfc61e..4c0848e765 100644 --- a/logging/test/logging_integration_test.dart +++ b/logging/test/logging_integration_test.dart @@ -6,6 +6,7 @@ import 'package:test/expect.dart'; import 'package:test/scaffolding.dart'; import 'mock_hub.dart'; +import 'dart:async'; void main() { late Fixture fixture; @@ -66,6 +67,29 @@ void main() { expect(fixture.hub.breadcrumbs.length, 1); }); + test('passes log record as hint', () async { + final sut = fixture.createSut(minEventLevel: Level.WARNING); + await sut.call(fixture.hub, fixture.options); + + final exception = Exception('foo bar'); + final stackTrace = StackTrace.current; + + final log = Logger('FooBarLogger'); + log.warning( + 'A log message', + exception, + stackTrace, + ); + + expect(fixture.hub.hints.length, 1); + final recordedHint = fixture.hub.hints.first.get('record') as LogRecord; + + expect(recordedHint.level, Level.WARNING); + expect(recordedHint.message, 'A log message'); + expect(recordedHint.error, exception); + expect(recordedHint.stackTrace, stackTrace); + }); + test('logger gets not recorded if level under minlevel', () async { final sut = fixture.createSut(minBreadcrumbLevel: Level.SEVERE); await sut.call(fixture.hub, fixture.options); diff --git a/logging/test/mock_hub.dart b/logging/test/mock_hub.dart index 30049452d2..8a0bf2aff4 100644 --- a/logging/test/mock_hub.dart +++ b/logging/test/mock_hub.dart @@ -10,6 +10,7 @@ class MockHub with NoSuchMethodProvider implements Hub { final List breadcrumbs = []; final List events = []; final _options = SentryOptions(dsn: 'fixture-dsn'); + final List hints = []; @override @internal @@ -28,6 +29,9 @@ class MockHub with NoSuchMethodProvider implements Hub { ScopeCallback? withScope, }) async { events.add(CapturedEvents(event, stackTrace)); + if (hint != null) { + hints.add(hint); + } return SentryId.newId(); } } From 8acb622f3a5fe24dbd00d83e1502975a0ac00c2e Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 11:29:01 +0100 Subject: [PATCH 12/38] pass on record hint to breadcrumb --- logging/lib/src/logging_integration.dart | 5 +++- logging/test/logging_integration_test.dart | 33 ++++++++++++++-------- logging/test/mock_hub.dart | 8 ++++-- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/logging/lib/src/logging_integration.dart b/logging/lib/src/logging_integration.dart index 05a801ba0e..f2da78f1b2 100644 --- a/logging/lib/src/logging_integration.dart +++ b/logging/lib/src/logging_integration.dart @@ -63,7 +63,10 @@ class LoggingIntegration extends Integration { } if (_isLoggable(record.level, _minBreadcrumbLevel)) { - await _hub.addBreadcrumb(record.toBreadcrumb()); + await _hub.addBreadcrumb( + record.toBreadcrumb(), + hint: Hint.fromMap({'record': record}), + ); } } } diff --git a/logging/test/logging_integration_test.dart b/logging/test/logging_integration_test.dart index 4c0848e765..4e823cc754 100644 --- a/logging/test/logging_integration_test.dart +++ b/logging/test/logging_integration_test.dart @@ -67,27 +67,38 @@ void main() { expect(fixture.hub.breadcrumbs.length, 1); }); - test('passes log record as hint', () async { - final sut = fixture.createSut(minEventLevel: Level.WARNING); + test('passes log records as hints', () async { + final sut = fixture.createSut( + minBreadcrumbLevel: Level.INFO, minEventLevel: Level.WARNING); await sut.call(fixture.hub, fixture.options); + final logger = Logger('FooBarLogger'); + + logger.info( + 'An info message', + ); + + expect(fixture.hub.breadcrumbHints.length, 1); + final breadcrumbHint = + fixture.hub.breadcrumbHints.first.get('record') as LogRecord; + + expect(breadcrumbHint.level, Level.INFO); + expect(breadcrumbHint.message, 'An info message'); final exception = Exception('foo bar'); final stackTrace = StackTrace.current; - - final log = Logger('FooBarLogger'); - log.warning( + logger.warning( 'A log message', exception, stackTrace, ); - expect(fixture.hub.hints.length, 1); - final recordedHint = fixture.hub.hints.first.get('record') as LogRecord; + expect(fixture.hub.eventHints.length, 1); + final errorHint = fixture.hub.eventHints.first.get('record') as LogRecord; - expect(recordedHint.level, Level.WARNING); - expect(recordedHint.message, 'A log message'); - expect(recordedHint.error, exception); - expect(recordedHint.stackTrace, stackTrace); + expect(errorHint.level, Level.WARNING); + expect(errorHint.message, 'A log message'); + expect(errorHint.error, exception); + expect(errorHint.stackTrace, stackTrace); }); test('logger gets not recorded if level under minlevel', () async { diff --git a/logging/test/mock_hub.dart b/logging/test/mock_hub.dart index 8a0bf2aff4..e12a66af30 100644 --- a/logging/test/mock_hub.dart +++ b/logging/test/mock_hub.dart @@ -10,7 +10,8 @@ class MockHub with NoSuchMethodProvider implements Hub { final List breadcrumbs = []; final List events = []; final _options = SentryOptions(dsn: 'fixture-dsn'); - final List hints = []; + final List breadcrumbHints = []; + final List eventHints = []; @override @internal @@ -19,6 +20,9 @@ class MockHub with NoSuchMethodProvider implements Hub { @override Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async { breadcrumbs.add(crumb); + if (hint != null) { + breadcrumbHints.add(hint); + } } @override @@ -30,7 +34,7 @@ class MockHub with NoSuchMethodProvider implements Hub { }) async { events.add(CapturedEvents(event, stackTrace)); if (hint != null) { - hints.add(hint); + eventHints.add(hint); } return SentryId.newId(); } From bac0e1dcb4c39ecd6f606a29278f14b07db91fb1 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 11:29:46 +0100 Subject: [PATCH 13/38] remove unused import --- logging/test/logging_integration_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/logging/test/logging_integration_test.dart b/logging/test/logging_integration_test.dart index 4e823cc754..fc540745e3 100644 --- a/logging/test/logging_integration_test.dart +++ b/logging/test/logging_integration_test.dart @@ -6,7 +6,6 @@ import 'package:test/expect.dart'; import 'package:test/scaffolding.dart'; import 'mock_hub.dart'; -import 'dart:async'; void main() { late Fixture fixture; From 51b6b2689986d6d87aa59b880cca6b6eb1f3b412 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 13:30:00 +0100 Subject: [PATCH 14/38] pass on errorDetails as hint in FlutterErrorIntegration --- flutter/lib/src/default_integrations.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flutter/lib/src/default_integrations.dart b/flutter/lib/src/default_integrations.dart index 7796c9c9c7..a8c3ebb71d 100644 --- a/flutter/lib/src/default_integrations.dart +++ b/flutter/lib/src/default_integrations.dart @@ -99,7 +99,9 @@ class FlutterErrorIntegration extends Integration { : null, ); - await hub.captureEvent(event, stackTrace: errorDetails.stack); + await hub.captureEvent(event, + stackTrace: errorDetails.stack, + hint: Hint.fromMap({'errorDetails': errorDetails})); // we don't call Zone.current.handleUncaughtError because we'd like // to set a specific mechanism for FlutterError.onError. } else { From cd719b2d7f4717ef6321d1d5b24b0f855f91462f Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 13:32:38 +0100 Subject: [PATCH 15/38] pass on request and requestDuration --- dart/lib/src/http_client/failed_request_client.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 3dd1377783..eefae2dd21 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -1,4 +1,5 @@ import 'package:http/http.dart'; +import '../hint.dart'; import 'sentry_http_client_error.dart'; import '../protocol.dart'; import '../hub.dart'; @@ -166,7 +167,12 @@ class FailedRequestClient extends BaseClient { throwable: throwableMechanism, request: sentryRequest, ); - await _hub.captureEvent(event, stackTrace: stackTrace); + await _hub.captureEvent( + event, + stackTrace: stackTrace, + hint: Hint.fromMap( + {'request': request, 'requestDuration': requestDuration}), + ); } // Types of Request can be found here: From 07a3c4e51d57f4eb5c366e4938eeaa892da03e07 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 13:58:18 +0100 Subject: [PATCH 16/38] test capture of request and requestDuration in hint --- .../failed_request_client_test.dart | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/dart/test/http_client/failed_request_client_test.dart b/dart/test/http_client/failed_request_client_test.dart index 361a83271a..eb58e0df71 100644 --- a/dart/test/http_client/failed_request_client_test.dart +++ b/dart/test/http_client/failed_request_client_test.dart @@ -219,6 +219,35 @@ void main() { ); } }); + + test('request and requestDuration are passed to hint', () async { + fixture._hub.options.captureFailedHttpRequests = true; + + Request? failedRequest; + final client = MockClient( + (request) async { + failedRequest = request; + throw TestException(); + }, + ); + + final sut = fixture.getSut(client: client); + + Hint? eventHint; + fixture.options + .addEventProcessor(FunctionEventProcessor((event, {hint}) async { + eventHint = hint; + return event; + })); + + await expectLater( + () async => await sut.get(requestUri), + throwsException, + ); + + expect((eventHint?.get('request') as Request?)?.url, failedRequest?.url); + expect(eventHint?.get('requestDuration'), isNotNull); + }); }); } @@ -234,12 +263,12 @@ MockClient createThrowingClient() { class CloseableMockClient extends Mock implements BaseClient {} class Fixture { - final _options = SentryOptions(dsn: fakeDsn); + final options = SentryOptions(dsn: fakeDsn); late Hub _hub; final transport = MockTransport(); Fixture() { - _options.transport = transport; - _hub = Hub(_options); + options.transport = transport; + _hub = Hub(options); } FailedRequestClient getSut({ From dfbd133451e6ef6042b539849329a62dc92bc40d Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 21 Nov 2022 14:20:41 +0100 Subject: [PATCH 17/38] pass print callback values from runzonedguarded integration --- dart/lib/src/default_integrations.dart | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dart/lib/src/default_integrations.dart b/dart/lib/src/default_integrations.dart index 758bf62182..71256e9bdf 100644 --- a/dart/lib/src/default_integrations.dart +++ b/dart/lib/src/default_integrations.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'hint.dart'; import 'hub.dart'; import 'integration.dart'; import 'protocol.dart'; @@ -81,10 +82,20 @@ class RunZonedGuardedIntegration extends Integration { _isPrinting = true; try { - hub.addBreadcrumb(Breadcrumb.console( - message: line, - level: SentryLevel.debug, - )); + hub.addBreadcrumb( + Breadcrumb.console( + message: line, + level: SentryLevel.debug, + ), + hint: Hint.fromMap( + { + 'self': self, + 'parent': parent, + 'zone': zone, + 'line': line, + }, + ), + ); parent.print(zone, line); } finally { From 729ec1bee1890f8598a8137733075c8987e95a50 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 22 Nov 2022 16:43:23 +0100 Subject: [PATCH 18/38] remove not needed hint --- dart/lib/src/run_zoned_guarded_integration.dart | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dart/lib/src/run_zoned_guarded_integration.dart b/dart/lib/src/run_zoned_guarded_integration.dart index 98e1f7fb22..dd0b820536 100644 --- a/dart/lib/src/run_zoned_guarded_integration.dart +++ b/dart/lib/src/run_zoned_guarded_integration.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'hint.dart'; import 'hub.dart'; import 'integration.dart'; import 'protocol.dart'; @@ -88,14 +87,6 @@ class RunZonedGuardedIntegration extends Integration { message: line, level: SentryLevel.debug, ), - hint: Hint.fromMap( - { - 'self': self, - 'parent': parent, - 'zone': zone, - 'line': line, - }, - ), ); parent.print(zone, line); From a586aaac818ca95eff376c297575ec13f457060d Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 22 Nov 2022 16:52:19 +0100 Subject: [PATCH 19/38] change constructor to factory --- dart/lib/src/hint.dart | 10 ++++++++-- dart/lib/src/http_client/failed_request_client.dart | 2 +- dart/test/hint_test.dart | 4 ++-- logging/lib/src/logging_integration.dart | 4 ++-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 7994187383..39816b54ab 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -3,12 +3,18 @@ class Hint { Hint(); - Hint.fromMap(Map map) { - _internalStorage.addAll(map); + factory Hint.withMap(Map map) { + final hint = Hint(); + hint.addAll(map); + return hint; } // Objects + void addAll(Map keysAndValues) { + _internalStorage.addAll(keysAndValues); + } + void set(String key, Object value) { _internalStorage[key] = value; } diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 99e89df8c3..03135d38bb 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -188,7 +188,7 @@ class FailedRequestClient extends BaseClient { await _hub.captureEvent( event, stackTrace: stackTrace, - hint: Hint.fromMap( + hint: Hint.withMap( {'request': request, 'requestDuration': requestDuration}), ); } diff --git a/dart/test/hint_test.dart b/dart/test/hint_test.dart index 7176c21020..e0b686820f 100644 --- a/dart/test/hint_test.dart +++ b/dart/test/hint_test.dart @@ -2,8 +2,8 @@ import 'package:sentry/src/hint.dart'; import 'package:test/test.dart'; void main() { - test('Hint init from map', () { - final hint = Hint.fromMap({'fixture-key': 'fixture-value'}); + test('Hint init with map', () { + final hint = Hint.withMap({'fixture-key': 'fixture-value'}); expect("fixture-value", hint.get("fixture-key")); }); diff --git a/logging/lib/src/logging_integration.dart b/logging/lib/src/logging_integration.dart index f2da78f1b2..ddd80adabb 100644 --- a/logging/lib/src/logging_integration.dart +++ b/logging/lib/src/logging_integration.dart @@ -58,14 +58,14 @@ class LoggingIntegration extends Integration { await _hub.captureEvent( record.toEvent(), stackTrace: record.stackTrace, - hint: Hint.fromMap({'record': record}), + hint: Hint.withMap({'record': record}), ); } if (_isLoggable(record.level, _minBreadcrumbLevel)) { await _hub.addBreadcrumb( record.toBreadcrumb(), - hint: Hint.fromMap({'record': record}), + hint: Hint.withMap({'record': record}), ); } } From 1c93a968f637e22f7d767ce96d23de69126660ba Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 22 Nov 2022 16:56:32 +0100 Subject: [PATCH 20/38] add response to hint --- dart/lib/src/http_client/failed_request_client.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 03135d38bb..60b44fdfdc 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -177,19 +177,22 @@ class FailedRequestClient extends BaseClient { timestamp: _hub.options.clock(), ); + final hint = + Hint.withMap({'request': request, 'requestDuration': requestDuration}); + if (response != null) { event.contexts.response = SentryResponse( headers: _hub.options.sendDefaultPii ? response.headers : null, bodySize: response.contentLength, statusCode: response.statusCode, ); + hint.set('response', response); } await _hub.captureEvent( event, stackTrace: stackTrace, - hint: Hint.withMap( - {'request': request, 'requestDuration': requestDuration}), + hint: hint, ); } From 855f3665fe5b67383da6062e93067bcfe82f2a04 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 22 Nov 2022 17:18:15 +0100 Subject: [PATCH 21/38] use syntheticException key --- dart/lib/src/hint.dart | 2 ++ flutter/lib/src/integrations/flutter_error_integration.dart | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 39816b54ab..d5d48035f2 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,6 +1,8 @@ class Hint { final Map _internalStorage = {}; + static const syntheticExceptionKey = 'syntheticException'; + Hint(); factory Hint.withMap(Map map) { diff --git a/flutter/lib/src/integrations/flutter_error_integration.dart b/flutter/lib/src/integrations/flutter_error_integration.dart index b4b3d5892f..13a24c7b29 100644 --- a/flutter/lib/src/integrations/flutter_error_integration.dart +++ b/flutter/lib/src/integrations/flutter_error_integration.dart @@ -78,7 +78,10 @@ class FlutterErrorIntegration extends Integration { timestamp: options.clock(), ); - await hub.captureEvent(event, stackTrace: errorDetails.stack); + await hub.captureEvent( + event, + stackTrace: errorDetails.stack, + hint: Hint.withMap({Hint.syntheticExceptionKey: errorDetails})); // we don't call Zone.current.handleUncaughtError because we'd like // to set a specific mechanism for FlutterError.onError. } else { From 8347d0755b121fc535538dd332dee6267e5a8bec Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 5 Dec 2022 11:30:26 +0100 Subject: [PATCH 22/38] move hint to captured event --- .../lib/src/integrations/flutter_error_integration.dart | 3 +-- logging/test/logging_integration_test.dart | 4 ++-- logging/test/mock_hub.dart | 9 +++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/flutter/lib/src/integrations/flutter_error_integration.dart b/flutter/lib/src/integrations/flutter_error_integration.dart index 13a24c7b29..09898956ff 100644 --- a/flutter/lib/src/integrations/flutter_error_integration.dart +++ b/flutter/lib/src/integrations/flutter_error_integration.dart @@ -78,8 +78,7 @@ class FlutterErrorIntegration extends Integration { timestamp: options.clock(), ); - await hub.captureEvent( - event, + await hub.captureEvent(event, stackTrace: errorDetails.stack, hint: Hint.withMap({Hint.syntheticExceptionKey: errorDetails})); // we don't call Zone.current.handleUncaughtError because we'd like diff --git a/logging/test/logging_integration_test.dart b/logging/test/logging_integration_test.dart index fc540745e3..fcc1b127c8 100644 --- a/logging/test/logging_integration_test.dart +++ b/logging/test/logging_integration_test.dart @@ -91,8 +91,8 @@ void main() { stackTrace, ); - expect(fixture.hub.eventHints.length, 1); - final errorHint = fixture.hub.eventHints.first.get('record') as LogRecord; + expect(fixture.hub.events.length, 1); + final errorHint = fixture.hub.events.first.hint?.get('record') as LogRecord; expect(errorHint.level, Level.WARNING); expect(errorHint.message, 'A log message'); diff --git a/logging/test/mock_hub.dart b/logging/test/mock_hub.dart index e12a66af30..0189dc902c 100644 --- a/logging/test/mock_hub.dart +++ b/logging/test/mock_hub.dart @@ -11,7 +11,6 @@ class MockHub with NoSuchMethodProvider implements Hub { final List events = []; final _options = SentryOptions(dsn: 'fixture-dsn'); final List breadcrumbHints = []; - final List eventHints = []; @override @internal @@ -32,17 +31,15 @@ class MockHub with NoSuchMethodProvider implements Hub { Hint? hint, ScopeCallback? withScope, }) async { - events.add(CapturedEvents(event, stackTrace)); - if (hint != null) { - eventHints.add(hint); - } + events.add(CapturedEvents(event, stackTrace, hint)); return SentryId.newId(); } } class CapturedEvents { - CapturedEvents(this.event, this.stackTrace); + CapturedEvents(this.event, this.stackTrace, this.hint); final SentryEvent event; final dynamic stackTrace; + final Hint? hint; } From 74966cd061221256afb6d4e69a27af971cef3aa1 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 5 Dec 2022 11:35:49 +0100 Subject: [PATCH 23/38] intruduce capturedbreadcrum similar to capturedevent in mock --- logging/test/logging_integration_test.dart | 6 +++--- logging/test/mock_hub.dart | 15 +++++++++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/logging/test/logging_integration_test.dart b/logging/test/logging_integration_test.dart index fcc1b127c8..e486b8f4b5 100644 --- a/logging/test/logging_integration_test.dart +++ b/logging/test/logging_integration_test.dart @@ -43,7 +43,7 @@ void main() { expect(fixture.hub.events.length, 0); expect(fixture.hub.breadcrumbs.length, 1); - final crumb = fixture.hub.breadcrumbs.first; + final crumb = fixture.hub.breadcrumbs.first.breadcrumb; expect(crumb.level, SentryLevel.warning); expect(crumb.message, 'A log message'); expect(crumb.data, { @@ -76,9 +76,9 @@ void main() { 'An info message', ); - expect(fixture.hub.breadcrumbHints.length, 1); + expect(fixture.hub.breadcrumbs.length, 1); final breadcrumbHint = - fixture.hub.breadcrumbHints.first.get('record') as LogRecord; + fixture.hub.breadcrumbs.first.hint?.get('record') as LogRecord; expect(breadcrumbHint.level, Level.INFO); expect(breadcrumbHint.message, 'An info message'); diff --git a/logging/test/mock_hub.dart b/logging/test/mock_hub.dart index 0189dc902c..3dcb1d4fc8 100644 --- a/logging/test/mock_hub.dart +++ b/logging/test/mock_hub.dart @@ -7,10 +7,9 @@ import 'no_such_method_provider.dart'; final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; class MockHub with NoSuchMethodProvider implements Hub { - final List breadcrumbs = []; + final List breadcrumbs = []; final List events = []; final _options = SentryOptions(dsn: 'fixture-dsn'); - final List breadcrumbHints = []; @override @internal @@ -18,10 +17,7 @@ class MockHub with NoSuchMethodProvider implements Hub { @override Future addBreadcrumb(Breadcrumb crumb, {Hint? hint}) async { - breadcrumbs.add(crumb); - if (hint != null) { - breadcrumbHints.add(hint); - } + breadcrumbs.add(CapturedBreadcrumb(crumb, hint)); } @override @@ -43,3 +39,10 @@ class CapturedEvents { final dynamic stackTrace; final Hint? hint; } + +class CapturedBreadcrumb { + CapturedBreadcrumb(this.breadcrumb, this.hint); + + final Breadcrumb breadcrumb; + final Hint? hint; +} From 9ea4b9909cdca5d393579fbe54c32593908a3099 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 5 Dec 2022 14:24:15 +0100 Subject: [PATCH 24/38] introduce TypeCheckHint class with constants --- dart/lib/sentry.dart | 1 + dart/lib/src/hint.dart | 2 -- dart/lib/src/type_check_hint.dart | 5 +++++ flutter/lib/src/integrations/flutter_error_integration.dart | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 dart/lib/src/type_check_hint.dart diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index de25791250..4c0633a17e 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -31,3 +31,4 @@ export 'src/utils/tracing_utils.dart'; // tracing export 'src/tracing.dart'; export 'src/hint.dart'; +export 'src/type_check_hint.dart'; diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index d5d48035f2..39816b54ab 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,8 +1,6 @@ class Hint { final Map _internalStorage = {}; - static const syntheticExceptionKey = 'syntheticException'; - Hint(); factory Hint.withMap(Map map) { diff --git a/dart/lib/src/type_check_hint.dart b/dart/lib/src/type_check_hint.dart new file mode 100644 index 0000000000..27acacaaf4 --- /dev/null +++ b/dart/lib/src/type_check_hint.dart @@ -0,0 +1,5 @@ +/// Constants used for Type Check hints. +class TypeCheckHint { + /// Used for Synthetic exceptions. + static const syntheticException = 'syntheticException'; +} diff --git a/flutter/lib/src/integrations/flutter_error_integration.dart b/flutter/lib/src/integrations/flutter_error_integration.dart index 09898956ff..e23ecc5d55 100644 --- a/flutter/lib/src/integrations/flutter_error_integration.dart +++ b/flutter/lib/src/integrations/flutter_error_integration.dart @@ -80,7 +80,8 @@ class FlutterErrorIntegration extends Integration { await hub.captureEvent(event, stackTrace: errorDetails.stack, - hint: Hint.withMap({Hint.syntheticExceptionKey: errorDetails})); + hint: + Hint.withMap({TypeCheckHint.syntheticException: errorDetails})); // we don't call Zone.current.handleUncaughtError because we'd like // to set a specific mechanism for FlutterError.onError. } else { From 910529948f18320c857225ac02e8d3ebe8b913eb Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 10:14:21 +0100 Subject: [PATCH 25/38] fix merge issue in DioEventProcessor --- dio/lib/src/dio_event_processor.dart | 35 ---------------------------- 1 file changed, 35 deletions(-) diff --git a/dio/lib/src/dio_event_processor.dart b/dio/lib/src/dio_event_processor.dart index ea447836a1..7f17a4bc69 100644 --- a/dio/lib/src/dio_event_processor.dart +++ b/dio/lib/src/dio_event_processor.dart @@ -139,41 +139,6 @@ class DioEventProcessor implements EventProcessor { return null; } - SentryResponse? _responseFrom(DioError dioError) { - final response = dioError.response; - - final headers = response?.headers.map.map( - (key, value) => MapEntry(key, value.join('; ')), - ); - - return SentryResponse( - headers: _options.sendDefaultPii ? headers : null, - url: response?.realUri.toString(), - redirected: response?.isRedirect, - body: _getResponseData(dioError.response?.data), - statusCode: response?.statusCode, - status: response?.statusMessage, - ); - } - - /// Returns the request data, if possible according to the users settings. - /// Type checks are based on DIOs [ResponseType]. - Object? _getResponseData(dynamic data) { - if (!_options.sendDefaultPii) { - return null; - } - if (data is String) { - if (_options.maxResponseBodySize.shouldAddBody(data.codeUnits.length)) { - return data; - } - } else if (data is List) { - if (_options.maxResponseBodySize.shouldAddBody(data.length)) { - return data; - } - } - return null; - } - SentryResponse _responseFrom(DioError dioError) { final response = dioError.response; From fbddcc4c52e05705da3841f4c164adc0e3109c63 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 10:23:07 +0100 Subject: [PATCH 26/38] add to type check hints --- dart/lib/src/http_client/failed_request_client.dart | 9 ++++++--- dart/lib/src/type_check_hint.dart | 9 +++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 60b44fdfdc..5bb2da43ca 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -1,4 +1,5 @@ import 'package:http/http.dart'; +import '../../sentry.dart'; import '../hint.dart'; import 'sentry_http_client_error.dart'; import '../protocol.dart'; @@ -177,8 +178,10 @@ class FailedRequestClient extends BaseClient { timestamp: _hub.options.clock(), ); - final hint = - Hint.withMap({'request': request, 'requestDuration': requestDuration}); + final hint = Hint.withMap({ + TypeCheckHint.httpRequest: request, + TypeCheckHint.httpRequestDuration: requestDuration, + }); if (response != null) { event.contexts.response = SentryResponse( @@ -186,7 +189,7 @@ class FailedRequestClient extends BaseClient { bodySize: response.contentLength, statusCode: response.statusCode, ); - hint.set('response', response); + hint.set(TypeCheckHint.httpResponse, response); } await _hub.captureEvent( diff --git a/dart/lib/src/type_check_hint.dart b/dart/lib/src/type_check_hint.dart index 27acacaaf4..0b0e61da24 100644 --- a/dart/lib/src/type_check_hint.dart +++ b/dart/lib/src/type_check_hint.dart @@ -2,4 +2,13 @@ class TypeCheckHint { /// Used for Synthetic exceptions. static const syntheticException = 'syntheticException'; + + /// Used for `FailedRequestClient` for request hint + static const httpRequest = 'request'; + + /// Used for `FailedRequestClient` for request duration hint + static const httpRequestDuration = 'requestDuration'; + + /// Used for `FailedRequestClient` for response hint + static const httpResponse = 'response'; } From cf57655a1bc3126e32262ac22603deef15f88fe2 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 10:25:46 +0100 Subject: [PATCH 27/38] add TypeCheckHint.record --- dart/lib/src/type_check_hint.dart | 9 ++++++--- logging/lib/src/logging_integration.dart | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/dart/lib/src/type_check_hint.dart b/dart/lib/src/type_check_hint.dart index 0b0e61da24..52dfdd5dea 100644 --- a/dart/lib/src/type_check_hint.dart +++ b/dart/lib/src/type_check_hint.dart @@ -3,12 +3,15 @@ class TypeCheckHint { /// Used for Synthetic exceptions. static const syntheticException = 'syntheticException'; - /// Used for `FailedRequestClient` for request hint + /// Used for [FailedRequestClient] for request hint static const httpRequest = 'request'; - /// Used for `FailedRequestClient` for request duration hint + /// Used for [FailedRequestClient] for request duration hint static const httpRequestDuration = 'requestDuration'; - /// Used for `FailedRequestClient` for response hint + /// Used for [FailedRequestClient] for response hint static const httpResponse = 'response'; + + /// Used for [LoggingIntegration] for [LogRecord] hint + static const record = 'record'; } diff --git a/logging/lib/src/logging_integration.dart b/logging/lib/src/logging_integration.dart index ddd80adabb..1ef6ea0a5c 100644 --- a/logging/lib/src/logging_integration.dart +++ b/logging/lib/src/logging_integration.dart @@ -58,14 +58,14 @@ class LoggingIntegration extends Integration { await _hub.captureEvent( record.toEvent(), stackTrace: record.stackTrace, - hint: Hint.withMap({'record': record}), + hint: Hint.withMap({TypeCheckHint.record: record}), ); } if (_isLoggable(record.level, _minBreadcrumbLevel)) { await _hub.addBreadcrumb( record.toBreadcrumb(), - hint: Hint.withMap({'record': record}), + hint: Hint.withMap({TypeCheckHint.record: record}), ); } } From 69a875ccf9e49125a2ca71e2bc83f93c22762863 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 11:00:24 +0100 Subject: [PATCH 28/38] fix tests --- ...atform_exception_event_processor_test.dart | 1 + ...flutter_enricher_event_processor_test.dart | 12 ++++++----- .../flutter_error_integration_test.dart | 20 ++++++++++++------- .../load_release_integration_test.dart | 6 ++++++ flutter/test/sentry_flutter_test.dart | 12 ++++++----- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/flutter/test/android_platform_exception_event_processor_test.dart b/flutter/test/android_platform_exception_event_processor_test.dart index cbc375b837..bfd8e2b4ce 100644 --- a/flutter/test/android_platform_exception_event_processor_test.dart +++ b/flutter/test/android_platform_exception_event_processor_test.dart @@ -20,6 +20,7 @@ void main() { buildSignature: '', packageName: 'io.sentry.samples', version: '1.2.3', + installerStore: null, ); }); 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 0648d74abc..5b8dbe51b1 100644 --- a/flutter/test/event_processor/flutter_enricher_event_processor_test.dart +++ b/flutter/test/event_processor/flutter_enricher_event_processor_test.dart @@ -304,9 +304,11 @@ class Fixture { void loadTestPackage() { PackageInfo.setMockInitialValues( - appName: 'appName', - packageName: 'packageName', - version: 'version', - buildNumber: 'buildNumber', - buildSignature: ''); + appName: 'appName', + packageName: 'packageName', + version: 'version', + buildNumber: 'buildNumber', + buildSignature: '', + installerStore: null, + ); } diff --git a/flutter/test/integrations/flutter_error_integration_test.dart b/flutter/test/integrations/flutter_error_integration_test.dart index 6a1391a19d..387fe09ee3 100644 --- a/flutter/test/integrations/flutter_error_integration_test.dart +++ b/flutter/test/integrations/flutter_error_integration_test.dart @@ -28,6 +28,9 @@ void main() { when(fixture.hub.captureEvent(captureAny)) .thenAnswer((_) => Future.value(SentryId.empty())); + when(fixture.hub.captureEvent(captureAny, hint: anyNamed('hint'))) + .thenAnswer((_) => Future.value(SentryId.empty())); + FlutterErrorIntegration()(fixture.hub, fixture.options); final throwable = exception ?? StateError('error'); @@ -47,7 +50,7 @@ void main() { _reportError(exception: exception); final event = verify( - await fixture.hub.captureEvent(captureAny), + await fixture.hub.captureEvent(captureAny, hint: anyNamed('hint')), ).captured.first as SentryEvent; expect(event.level, SentryLevel.fatal); @@ -83,7 +86,7 @@ void main() { _reportError(exception: StateError('error'), optionalDetails: details); final event = verify( - await fixture.hub.captureEvent(captureAny), + await fixture.hub.captureEvent(captureAny, hint: anyNamed('hint')), ).captured.first as SentryEvent; expect(event.level, SentryLevel.fatal); @@ -109,7 +112,7 @@ void main() { _reportError(exception: StateError('error'), optionalDetails: details); final event = verify( - await fixture.hub.captureEvent(captureAny), + await fixture.hub.captureEvent(captureAny, hint: anyNamed('hint')), ).captured.first as SentryEvent; expect(event.level, SentryLevel.fatal); @@ -130,7 +133,8 @@ void main() { _reportError(handler: defaultError); - verify(await fixture.hub.captureEvent(captureAny)); + verify( + await fixture.hub.captureEvent(captureAny, hint: anyNamed('hint'))); expect(called, true); }); @@ -142,7 +146,7 @@ void main() { }; FlutterError.onError = defaultError; - when(fixture.hub.captureEvent(captureAny)) + when(fixture.hub.captureEvent(captureAny, hint: anyNamed('hint'))) .thenAnswer((_) => Future.value(SentryId.empty())); final details = FlutterErrorDetails(exception: StateError('error')); @@ -156,7 +160,8 @@ void main() { FlutterError.reportError(details); - verify(await fixture.hub.captureEvent(captureAny)).called(1); + verify(await fixture.hub.captureEvent(captureAny, hint: anyNamed('hint'))) + .called(1); expect(numberOfDefaultCalls, 1); }); @@ -202,7 +207,8 @@ void main() { fixture.options.reportSilentFlutterErrors = true; _reportError(silent: true); - verify(await fixture.hub.captureEvent(captureAny)); + verify( + await fixture.hub.captureEvent(captureAny, hint: anyNamed('hint'))); }); test('FlutterError adds integration', () { diff --git a/flutter/test/integrations/load_release_integration_test.dart b/flutter/test/integrations/load_release_integration_test.dart index 857537f38d..5a9006fcd3 100644 --- a/flutter/test/integrations/load_release_integration_test.dart +++ b/flutter/test/integrations/load_release_integration_test.dart @@ -40,6 +40,7 @@ void main() { version: '1.2.3', buildNumber: '789', buildSignature: '', + installerStore: null, ); }; await fixture @@ -59,6 +60,7 @@ void main() { version: '1.2.3', buildNumber: '789', buildSignature: '', + installerStore: null, ); }; await fixture @@ -84,6 +86,7 @@ void main() { version: '1.0.0\u{0000}', buildNumber: '', buildSignature: '', + installerStore: null, ); }; await fixture @@ -109,6 +112,7 @@ void main() { version: '', buildNumber: '123\u{0000}', buildSignature: '', + installerStore: null, ); }; await fixture @@ -126,6 +130,7 @@ void main() { version: '1.0.0', buildNumber: '', buildSignature: '', + installerStore: null, ); }; await fixture @@ -157,6 +162,7 @@ class Fixture { version: '1.2.3', buildNumber: '789', buildSignature: '', + installerStore: null, ); } } diff --git a/flutter/test/sentry_flutter_test.dart b/flutter/test/sentry_flutter_test.dart index 36e19fdf51..c0698529ff 100644 --- a/flutter/test/sentry_flutter_test.dart +++ b/flutter/test/sentry_flutter_test.dart @@ -517,11 +517,13 @@ void appRunner() {} void loadTestPackage() { PackageInfo.setMockInitialValues( - appName: 'appName', - packageName: 'packageName', - version: 'version', - buildNumber: 'buildNumber', - buildSignature: ''); + appName: 'appName', + packageName: 'packageName', + version: 'version', + buildNumber: 'buildNumber', + buildSignature: '', + installerStore: null, + ); } PlatformChecker getPlatformChecker({ From 1d7924f425771f977cb8cc11a3117ab5bd6cf283 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 11:18:02 +0100 Subject: [PATCH 29/38] fix imports --- dart/lib/src/http_client/failed_request_client.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 5bb2da43ca..9b3d3aca8f 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -1,6 +1,6 @@ import 'package:http/http.dart'; -import '../../sentry.dart'; import '../hint.dart'; +import '../type_check_hint.dart'; import 'sentry_http_client_error.dart'; import '../protocol.dart'; import '../hub.dart'; From 7e72222adee4151b0be590ad1c982990388880e2 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 11:29:03 +0100 Subject: [PATCH 30/38] add required trailing comma --- logging/test/logging_integration_test.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/logging/test/logging_integration_test.dart b/logging/test/logging_integration_test.dart index e486b8f4b5..aeaf7877bf 100644 --- a/logging/test/logging_integration_test.dart +++ b/logging/test/logging_integration_test.dart @@ -68,7 +68,9 @@ void main() { test('passes log records as hints', () async { final sut = fixture.createSut( - minBreadcrumbLevel: Level.INFO, minEventLevel: Level.WARNING); + minBreadcrumbLevel: Level.INFO, + minEventLevel: Level.WARNING, + ); await sut.call(fixture.hub, fixture.options); final logger = Logger('FooBarLogger'); From 6bf4a83a030c3d81a0a1859b6003cfd3a28bc683 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 11:57:54 +0100 Subject: [PATCH 31/38] remove disable of cyclomatic_complexity --- flutter/ios/Classes/SentryFlutterPluginApple.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/flutter/ios/Classes/SentryFlutterPluginApple.swift b/flutter/ios/Classes/SentryFlutterPluginApple.swift index 1466a51228..0e558ec512 100644 --- a/flutter/ios/Classes/SentryFlutterPluginApple.swift +++ b/flutter/ios/Classes/SentryFlutterPluginApple.swift @@ -126,7 +126,6 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { } } - // swiftlint:disable:next cyclomatic_complexity private func loadContexts(result: @escaping FlutterResult) { SentrySDK.configureScope { scope in let serializedScope = scope.serialize() From 4073333c6448beb62846d070deb7dafd7bc77710 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Tue, 6 Dec 2022 15:39:48 +0100 Subject: [PATCH 32/38] remove request duration hint --- dart/lib/src/http_client/failed_request_client.dart | 5 +---- dart/lib/src/type_check_hint.dart | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/dart/lib/src/http_client/failed_request_client.dart b/dart/lib/src/http_client/failed_request_client.dart index 9b3d3aca8f..c9a7d12db3 100644 --- a/dart/lib/src/http_client/failed_request_client.dart +++ b/dart/lib/src/http_client/failed_request_client.dart @@ -178,10 +178,7 @@ class FailedRequestClient extends BaseClient { timestamp: _hub.options.clock(), ); - final hint = Hint.withMap({ - TypeCheckHint.httpRequest: request, - TypeCheckHint.httpRequestDuration: requestDuration, - }); + final hint = Hint.withMap({TypeCheckHint.httpRequest: request}); if (response != null) { event.contexts.response = SentryResponse( diff --git a/dart/lib/src/type_check_hint.dart b/dart/lib/src/type_check_hint.dart index 52dfdd5dea..a6420e1f54 100644 --- a/dart/lib/src/type_check_hint.dart +++ b/dart/lib/src/type_check_hint.dart @@ -6,9 +6,6 @@ class TypeCheckHint { /// Used for [FailedRequestClient] for request hint static const httpRequest = 'request'; - /// Used for [FailedRequestClient] for request duration hint - static const httpRequestDuration = 'requestDuration'; - /// Used for [FailedRequestClient] for response hint static const httpResponse = 'response'; From 0021a6ab8a57b60731f110999e25bb0ffb58b23a Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 12 Dec 2022 10:30:39 +0100 Subject: [PATCH 33/38] fix issue in sentry user interaction widget --- dart/lib/src/type_check_hint.dart | 3 +++ .../src/user_interaction/sentry_user_interaction_widget.dart | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dart/lib/src/type_check_hint.dart b/dart/lib/src/type_check_hint.dart index a6420e1f54..5a217b4285 100644 --- a/dart/lib/src/type_check_hint.dart +++ b/dart/lib/src/type_check_hint.dart @@ -11,4 +11,7 @@ class TypeCheckHint { /// Used for [LoggingIntegration] for [LogRecord] hint static const record = 'record'; + + /// Widget that was tapped in [SentryUserInteractionWidget] + static const widget = 'widget'; } 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 86240954c4..6c92ba3321 100644 --- a/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart +++ b/flutter/lib/src/user_interaction/sentry_user_interaction_widget.dart @@ -131,7 +131,8 @@ class _SentryUserInteractionWidgetState viewClass: tappedWidget.type, // to avoid minification data: data, ); - _hub.addBreadcrumb(crumb, hint: element.widget); + final hint = Hint.withMap({TypeCheckHint.widget: element.widget}); + _hub.addBreadcrumb(crumb, hint: hint); } // ignore: invalid_use_of_internal_member From 0134de237101dcc718884221ef3ba7b033336750 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 12 Dec 2022 10:30:48 +0100 Subject: [PATCH 34/38] add comments for hint --- dart/lib/src/hint.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 39816b54ab..f438dca056 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,3 +1,10 @@ +/// Hints are used in [BeforeSendCallback], [BeforeBreadcrumbCallback] and +/// event processors. +/// +/// Event and breadcrumb hints are objects containing various information used +/// to put together an event or a breadcrumb. Typically hints hold the original +/// exception so that additional data can be extracted or grouping can be +/// affected. class Hint { final Map _internalStorage = {}; From 2f07ae02e2a663c93e196127de43a8992b4a5bc3 Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 12 Dec 2022 10:52:52 +0100 Subject: [PATCH 35/38] add sample code to hint description --- dart/lib/src/hint.dart | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index f438dca056..3754bbf0a0 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -5,6 +5,19 @@ /// to put together an event or a breadcrumb. Typically hints hold the original /// exception so that additional data can be extracted or grouping can be /// affected. +/// +/// Example: +/// +/// ```dart +/// options.beforeSend = (event, {hint}) { +/// final syntheticException = hint?.get(TypeCheckHint.syntheticException); +/// if (syntheticException is FlutterErrorDetails) { +/// // Do something with hint data +/// } +/// return event; +/// }; +/// } +/// ``` class Hint { final Map _internalStorage = {}; From 24b51c3637e0d7195c1c971a464b04759e0cf66a Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 12 Dec 2022 11:04:41 +0100 Subject: [PATCH 36/38] fix test --- dart/test/http_client/failed_request_client_test.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dart/test/http_client/failed_request_client_test.dart b/dart/test/http_client/failed_request_client_test.dart index 7843c9f345..78cf675bbe 100644 --- a/dart/test/http_client/failed_request_client_test.dart +++ b/dart/test/http_client/failed_request_client_test.dart @@ -250,7 +250,7 @@ void main() { } }); - test('request and requestDuration are passed to hint', () async { + test('request passed to hint', () async { fixture._hub.options.captureFailedHttpRequests = true; Request? failedRequest; @@ -276,7 +276,6 @@ void main() { ); expect((eventHint?.get('request') as Request?)?.url, failedRequest?.url); - expect(eventHint?.get('requestDuration'), isNotNull); }); }); } From 026605ef399cb8d853c9442a03b6b80b08bf7d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 12 Dec 2022 10:47:59 +0000 Subject: [PATCH 37/38] Feat: Use `Hint` for screenshots (#1165) --- CHANGELOG.md | 3 +- dart/lib/sentry_private.dart | 3 -- dart/lib/src/hint.dart | 10 ++++ dart/lib/src/sentry_client.dart | 12 ++--- .../sentry_client_attachment_processor.dart | 14 ----- dart/lib/src/sentry_options.dart | 5 -- dart/test/mocks.dart | 21 -------- dart/test/sentry_client_test.dart | 53 +++++-------------- flutter/example/lib/main.dart | 1 + .../screenshot_event_processor.dart} | 25 ++++----- .../integrations/screenshot_integration.dart | 20 +++---- .../screenshot_event_processor_test.dart} | 11 ++-- .../screenshot_integration_test.dart | 31 +++++------ min_version_test/lib/main.dart | 3 +- 14 files changed, 77 insertions(+), 135 deletions(-) delete mode 100644 dart/lib/sentry_private.dart delete mode 100644 dart/lib/src/sentry_client_attachment_processor.dart rename flutter/lib/src/{screenshot/screenshot_attachment_processor.dart => event_processor/screenshot_event_processor.dart} (80%) rename flutter/test/{screenshot/screenshot_attachment_processor_test.dart => event_processor/screenshot_event_processor_test.dart} (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index e389210497..9277ba18d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### Features -- Feat: Introduce Hint data bag ([#1136](https://github.com/getsentry/sentry-dart/pull/1136)) +- Feat: Introduce `Hint` data bag ([#1136](https://github.com/getsentry/sentry-dart/pull/1136)) +- Feat: Use `Hint` for screenshots ([#1165](https://github.com/getsentry/sentry-dart/pull/1165)) ### Fixes diff --git a/dart/lib/sentry_private.dart b/dart/lib/sentry_private.dart deleted file mode 100644 index 299519b7a5..0000000000 --- a/dart/lib/sentry_private.dart +++ /dev/null @@ -1,3 +0,0 @@ -// attachments -// ignore: invalid_export_of_internal_element -export 'src/sentry_client_attachment_processor.dart'; diff --git a/dart/lib/src/hint.dart b/dart/lib/src/hint.dart index 3754bbf0a0..bfe0dd9b38 100644 --- a/dart/lib/src/hint.dart +++ b/dart/lib/src/hint.dart @@ -1,3 +1,5 @@ +import 'sentry_attachment/sentry_attachment.dart'; + /// Hints are used in [BeforeSendCallback], [BeforeBreadcrumbCallback] and /// event processors. /// @@ -21,6 +23,8 @@ class Hint { final Map _internalStorage = {}; + SentryAttachment? screenshot; + Hint(); factory Hint.withMap(Map map) { @@ -29,6 +33,12 @@ class Hint { return hint; } + factory Hint.withScreenshot(SentryAttachment screenshot) { + final hint = Hint(); + hint.screenshot = screenshot; + return hint; + } + // Objects void addAll(Map keysAndValues) { diff --git a/dart/lib/src/sentry_client.dart b/dart/lib/src/sentry_client.dart index 498c13b662..77ee2f586a 100644 --- a/dart/lib/src/sentry_client.dart +++ b/dart/lib/src/sentry_client.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:math'; import 'package:meta/meta.dart'; +import 'sentry_attachment/sentry_attachment.dart'; import 'event_processor.dart'; import 'hint.dart'; @@ -20,7 +21,6 @@ import 'sentry_envelope.dart'; import 'client_reports/client_report_recorder.dart'; import 'client_reports/discard_reason.dart'; import 'transport/data_category.dart'; -import 'sentry_client_attachment_processor.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 @@ -39,9 +39,6 @@ class SentryClient { SentryStackTraceFactory get _stackTraceFactory => _options.stackTraceFactory; - SentryClientAttachmentProcessor get _clientAttachmentProcessor => - _options.clientAttachmentProcessor; - /// Instantiates a client using [SentryOptions] factory SentryClient(SentryOptions options) { if (options.sendClientReports) { @@ -137,8 +134,11 @@ class SentryClient { preparedEvent = _eventWithRemovedBreadcrumbsIfHandled(preparedEvent); } - final attachments = await _clientAttachmentProcessor.processAttachments( - scope?.attachments ?? [], preparedEvent); + var attachments = List.from(scope?.attachments ?? []); + var screenshot = hint.screenshot; + if (screenshot != null) { + attachments.add(screenshot); + } final envelope = SentryEnvelope.fromEvent( preparedEvent, diff --git a/dart/lib/src/sentry_client_attachment_processor.dart b/dart/lib/src/sentry_client_attachment_processor.dart deleted file mode 100644 index 32ed178244..0000000000 --- a/dart/lib/src/sentry_client_attachment_processor.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'dart:async'; - -import 'package:meta/meta.dart'; - -import './sentry_attachment/sentry_attachment.dart'; -import './protocol/sentry_event.dart'; - -@internal -class SentryClientAttachmentProcessor { - Future> processAttachments( - List attachments, SentryEvent event) async { - return attachments; - } -} diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 7765a6b517..054a9a9cb3 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -5,7 +5,6 @@ import 'package:meta/meta.dart'; import 'package:http/http.dart'; import '../sentry.dart'; -import '../sentry_private.dart'; import 'client_reports/client_report_recorder.dart'; import 'client_reports/noop_client_report_recorder.dart'; import 'sentry_exception_factory.dart'; @@ -389,10 +388,6 @@ class SentryOptions { late SentryStackTraceFactory stackTraceFactory = SentryStackTraceFactory(this); - @internal - late SentryClientAttachmentProcessor clientAttachmentProcessor = - SentryClientAttachmentProcessor(); - void _debugLogger( SentryLevel level, String message, { diff --git a/dart/test/mocks.dart b/dart/test/mocks.dart index a2b79b0dbe..55146df7bd 100644 --- a/dart/test/mocks.dart +++ b/dart/test/mocks.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; -import 'package:sentry/sentry_private.dart'; import 'package:sentry/src/transport/rate_limiter.dart'; final fakeDsn = 'https://abc@def.ingest.sentry.io/1234567'; @@ -159,23 +158,3 @@ class MockRateLimiter implements RateLimiter { this.errorCode = errorCode; } } - -enum MockAttachmentProcessorMode { filter, add } - -/// Filtering out all attachments. -class MockAttachmentProcessor implements SentryClientAttachmentProcessor { - MockAttachmentProcessorMode mode; - - MockAttachmentProcessor(this.mode); - - @override - Future> processAttachments( - List attachments, SentryEvent event) async { - switch (mode) { - case MockAttachmentProcessorMode.filter: - return []; - case MockAttachmentProcessorMode.add: - return [SentryAttachment.fromIntList([], "added")]; - } - } -} diff --git a/dart/test/sentry_client_test.dart b/dart/test/sentry_client_test.dart index c8eb8305fc..bd8890c479 100644 --- a/dart/test/sentry_client_test.dart +++ b/dart/test/sentry_client_test.dart @@ -1061,45 +1061,6 @@ void main() { }); }); - group('SentryClientAttachmentProcessor', () { - late Fixture fixture; - - setUp(() { - fixture = Fixture(); - }); - - test('processor filtering out attachments', () async { - fixture.options.clientAttachmentProcessor = - MockAttachmentProcessor(MockAttachmentProcessorMode.filter); - final scope = Scope(fixture.options); - scope.addAttachment(SentryAttachment.fromIntList([], "scope-attachment")); - final sut = fixture.getSut(); - - final event = SentryEvent(); - await sut.captureEvent(event, scope: scope); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final attachmentItem = capturedEnvelope.items.firstWhereOrNull( - (element) => element.header.type == SentryItemType.attachment); - expect(attachmentItem, null); - }); - - test('processor adding attachments', () async { - fixture.options.clientAttachmentProcessor = - MockAttachmentProcessor(MockAttachmentProcessorMode.add); - final scope = Scope(fixture.options); - final sut = fixture.getSut(); - - final event = SentryEvent(); - await sut.captureEvent(event, scope: scope); - - final capturedEnvelope = (fixture.transport).envelopes.first; - final attachmentItem = capturedEnvelope.items.firstWhereOrNull( - (element) => element.header.type == SentryItemType.attachment); - expect(attachmentItem != null, true); - }); - }); - group('ClientReportRecorder', () { late Fixture fixture; @@ -1171,6 +1132,20 @@ void main() { expect(envelope.header.traceContext, isNotNull); }); + test('captureEvent adds screenshot from hint', () async { + final client = fixture.getSut(); + final screenshot = + SentryAttachment.fromScreenshotData(Uint8List.fromList([0, 0, 0, 0])); + final hint = Hint.withScreenshot(screenshot); + + await client.captureEvent(fakeEvent, hint: hint); + + final capturedEnvelope = (fixture.transport).envelopes.first; + final attachmentItem = capturedEnvelope.items.firstWhereOrNull( + (element) => element.header.type == SentryItemType.attachment); + expect(attachmentItem != null, true); + }); + test('captureTransaction adds trace context', () async { final client = fixture.getSut(); diff --git a/flutter/example/lib/main.dart b/flutter/example/lib/main.dart index bfe301da07..04a23abeb1 100644 --- a/flutter/example/lib/main.dart +++ b/flutter/example/lib/main.dart @@ -58,6 +58,7 @@ Future setupSentry(AppRunner appRunner) async { options.captureFailedHttpRequests = true; options.maxRequestBodySize = MaxRequestBodySize.always; options.maxResponseBodySize = MaxResponseBodySize.always; + options.captureFailedHttpRequests = true; options.recordHttpBreadcrumbs = true; }, // Init your App. diff --git a/flutter/lib/src/screenshot/screenshot_attachment_processor.dart b/flutter/lib/src/event_processor/screenshot_event_processor.dart similarity index 80% rename from flutter/lib/src/screenshot/screenshot_attachment_processor.dart rename to flutter/lib/src/event_processor/screenshot_event_processor.dart index afc0f70989..3191fee364 100644 --- a/flutter/lib/src/screenshot/screenshot_attachment_processor.dart +++ b/flutter/lib/src/event_processor/screenshot_event_processor.dart @@ -2,45 +2,42 @@ import 'dart:async'; import 'dart:typed_data'; import 'dart:ui' as ui show ImageByteFormat; -import 'package:flutter/rendering.dart'; import 'package:sentry/sentry.dart'; -import 'package:sentry/sentry_private.dart'; -import '../renderer/renderer.dart'; +import '../screenshot/sentry_screenshot_widget.dart'; import '../sentry_flutter_options.dart'; -import 'sentry_screenshot_widget.dart'; +import 'package:flutter/rendering.dart'; +import '../renderer/renderer.dart'; -// ignore: invalid_use_of_internal_member -class ScreenshotAttachmentProcessor implements SentryClientAttachmentProcessor { +class ScreenshotEventProcessor extends EventProcessor { final SentryFlutterOptions _options; - ScreenshotAttachmentProcessor(this._options); + ScreenshotEventProcessor(this._options); /// This is true when the SentryWidget is in the view hierarchy bool get _hasSentryScreenshotWidget => sentryScreenshotWidgetGlobalKey.currentContext != null; @override - Future> processAttachments( - List attachments, SentryEvent event) async { + FutureOr apply(SentryEvent event, {hint}) async { if (event.exceptions == null && event.throwable == null && _hasSentryScreenshotWidget) { - return attachments; + return event; } + final renderer = _options.rendererWrapper.getRenderer(); if (renderer != FlutterRenderer.skia && renderer != FlutterRenderer.canvasKit) { _options.logger(SentryLevel.debug, 'Cannot take screenshot with ${_options.rendererWrapper.getRendererAsString()} renderer.'); - return attachments; + return event; } final bytes = await _createScreenshot(); if (bytes != null) { - return attachments + [SentryAttachment.fromScreenshotData(bytes)]; - } else { - return attachments; + hint?.screenshot = SentryAttachment.fromScreenshotData(bytes); } + return event; } Future _createScreenshot() async { diff --git a/flutter/lib/src/integrations/screenshot_integration.dart b/flutter/lib/src/integrations/screenshot_integration.dart index aa0e2abfc7..da8b5c9c51 100644 --- a/flutter/lib/src/integrations/screenshot_integration.dart +++ b/flutter/lib/src/integrations/screenshot_integration.dart @@ -1,29 +1,31 @@ import 'dart:async'; import 'package:sentry/sentry.dart'; -import 'package:sentry/sentry_private.dart'; -import '../screenshot/screenshot_attachment_processor.dart'; +import '../event_processor/screenshot_event_processor.dart'; import '../sentry_flutter_options.dart'; -/// Adds [ScreenshotAttachmentProcessor] to options if [attachScreenshot] is true +/// Adds [ScreenshotEventProcessor] to options event processors if [attachScreenshot] is true class ScreenshotIntegration implements Integration { SentryFlutterOptions? _options; + ScreenshotEventProcessor? screenshotEventProcessor; @override FutureOr call(Hub hub, SentryFlutterOptions options) { if (options.attachScreenshot) { - // ignore: invalid_use_of_internal_member - options.clientAttachmentProcessor = - ScreenshotAttachmentProcessor(options); _options = options; - + final screenshotEventProcessor = ScreenshotEventProcessor(options); + options.addEventProcessor(screenshotEventProcessor); + this.screenshotEventProcessor = screenshotEventProcessor; options.sdk.addIntegration('screenshotIntegration'); } } @override FutureOr close() { - // ignore: invalid_use_of_internal_member - _options?.clientAttachmentProcessor = SentryClientAttachmentProcessor(); + final screenshotEventProcessor = this.screenshotEventProcessor; + if (screenshotEventProcessor != null) { + _options?.removeEventProcessor(screenshotEventProcessor); + this.screenshotEventProcessor = null; + } } } diff --git a/flutter/test/screenshot/screenshot_attachment_processor_test.dart b/flutter/test/event_processor/screenshot_event_processor_test.dart similarity index 85% rename from flutter/test/screenshot/screenshot_attachment_processor_test.dart rename to flutter/test/event_processor/screenshot_event_processor_test.dart index c27c5b42a0..6b49f6457c 100644 --- a/flutter/test/screenshot/screenshot_attachment_processor_test.dart +++ b/flutter/test/event_processor/screenshot_event_processor_test.dart @@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:sentry_flutter/src/event_processor/screenshot_event_processor.dart'; import 'package:sentry_flutter/src/renderer/renderer.dart'; -import 'package:sentry_flutter/src/screenshot/screenshot_attachment_processor.dart'; import '../mocks.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -26,9 +26,10 @@ void main() { final throwable = Exception(); final event = SentryEvent(throwable: throwable); - final attachments = await sut.processAttachments([], event); + final hint = Hint(); + await sut.apply(event, hint: hint); - expect(attachments.isNotEmpty, added); + expect(hint.screenshot != null, added); }); } @@ -55,8 +56,8 @@ void main() { class Fixture { SentryFlutterOptions options = SentryFlutterOptions(dsn: fakeDsn); - ScreenshotAttachmentProcessor getSut(FlutterRenderer flutterRenderer) { + ScreenshotEventProcessor getSut(FlutterRenderer flutterRenderer) { options.rendererWrapper = MockRendererWrapper(flutterRenderer); - return ScreenshotAttachmentProcessor(options); + return ScreenshotEventProcessor(options); } } diff --git a/flutter/test/integrations/screenshot_integration_test.dart b/flutter/test/integrations/screenshot_integration_test.dart index bfd29ec8d6..8e31a107fb 100644 --- a/flutter/test/integrations/screenshot_integration_test.dart +++ b/flutter/test/integrations/screenshot_integration_test.dart @@ -1,7 +1,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:sentry_flutter/src/event_processor/screenshot_event_processor.dart'; import 'package:sentry_flutter/src/integrations/screenshot_integration.dart'; -import 'package:sentry_flutter/src/screenshot/screenshot_attachment_processor.dart'; import '../mocks.mocks.dart'; @@ -17,25 +17,23 @@ void main() { await integration(fixture.hub, fixture.options); - expect( - // ignore: invalid_use_of_internal_member - fixture.options.clientAttachmentProcessor - is ScreenshotAttachmentProcessor, - true); + final processors = fixture.options.eventProcessors + .where((e) => e.runtimeType == ScreenshotEventProcessor); + + expect(processors.isNotEmpty, true); }); test( - 'screenshotIntegration does not creates screenshot processor if opt out in options', + 'screenshotIntegration does not add screenshot processor if opt out in options', () async { final integration = fixture.getSut(attachScreenshot: false); await integration(fixture.hub, fixture.options); - expect( - // ignore: invalid_use_of_internal_member - fixture.options.clientAttachmentProcessor - is ScreenshotAttachmentProcessor, - false); + final processors = fixture.options.eventProcessors + .where((e) => e.runtimeType == ScreenshotEventProcessor); + + expect(processors.isEmpty, true); }); test('screenshotIntegration close resets processor', () async { @@ -44,11 +42,10 @@ void main() { await integration(fixture.hub, fixture.options); await integration.close(); - expect( - // ignore: invalid_use_of_internal_member - fixture.options.clientAttachmentProcessor - is ScreenshotAttachmentProcessor, - false); + final processors = fixture.options.eventProcessors + .where((e) => e.runtimeType == ScreenshotEventProcessor); + + expect(processors.isEmpty, true); }); } diff --git a/min_version_test/lib/main.dart b/min_version_test/lib/main.dart index e70e318bf2..afcfd61bca 100644 --- a/min_version_test/lib/main.dart +++ b/min_version_test/lib/main.dart @@ -44,6 +44,7 @@ Future setupSentry(AppRunner appRunner) async { // going to log too much for your app, but can be useful when figuring out // configuration issues, e.g. finding out why your events are not uploaded. options.debug = true; + options.captureFailedHttpRequests = true; }, // Init your App. appRunner: appRunner); @@ -111,7 +112,7 @@ class _MyHomePageState extends State { _counter++; final dio = Dio(); - dio.addSentry(captureFailedRequests: true); + dio.addSentry(); final log = Logger('_MyHomePageState'); try { From bfe155c9c6b4ec8a0e94084294223679d1db8dfa Mon Sep 17 00:00:00 2001 From: Denis Andrasec Date: Mon, 12 Dec 2022 13:32:44 +0100 Subject: [PATCH 38/38] remove not needed option setup --- flutter/example/lib/main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/flutter/example/lib/main.dart b/flutter/example/lib/main.dart index 04a23abeb1..e7c2ac718a 100644 --- a/flutter/example/lib/main.dart +++ b/flutter/example/lib/main.dart @@ -59,7 +59,6 @@ Future setupSentry(AppRunner appRunner) async { options.maxRequestBodySize = MaxRequestBodySize.always; options.maxResponseBodySize = MaxResponseBodySize.always; options.captureFailedHttpRequests = true; - options.recordHttpBreadcrumbs = true; }, // Init your App. appRunner: appRunner);