diff --git a/CHANGELOG.md b/CHANGELOG.md index 4917265a24..bbcd28ab28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ - remove the `package:args` dependency #94 - move the `package:pedantic` to dev depencies #94 - Added GH Action Changelog verifier #95 -- Added GH Action (CI) for Dart +- Added GH Action (CI) for Dart #97 - new Dart code file structure #96 - Base the sdk name on the platform (`sentry.dart` for io & flutter, `sentry.dart.browser` in a browser context) #103 - Single changelog and readme for both packages #105 @@ -22,10 +22,11 @@ - expect a sdkName based on the test platform #105 - Added Scope and Breadcrumb ring buffer #109 - Added Hub to SDK #113 -- Ref: Hub passes the Scope to SentryClient +- Ref: Hub passes the Scope to SentryClient #114 - Feature: sentry options #116 -- Ref: SentryId generates UUID -- Ref: Event now is SentryEvent and added GPU +- Ref: SentryId generates UUID #119 +- Ref: Event now is SentryEvent and added GPU #121 +- Feat: before breadcrumb and scope ref. #122 # `package:sentry` changelog diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart index 11c2530795..4927fcaa5b 100644 --- a/dart/lib/src/scope.dart +++ b/dart/lib/src/scope.dart @@ -6,32 +6,14 @@ import 'sentry_options.dart'; /// Scope data to be sent with the event class Scope { /// How important this event is. - SentryLevel _level; - - SentryLevel get level => _level; - - set level(SentryLevel level) { - _level = level; - } + SentryLevel level; /// The name of the transaction which generated this event, /// for example, the route name: `"/users//"`. - String _transaction; - - String get transaction => _transaction; - - set transaction(String transaction) { - _transaction = transaction; - } + String transaction; /// Information about the current user. - User _user; - - User get user => _user; - - set user(User user) { - _user = user; - } + User user; /// Used to deduplicate events by grouping ones with the same fingerprint /// together. @@ -71,14 +53,20 @@ class Scope { Map get extra => Map.unmodifiable(_extra); - // TODO: EventProcessors, Contexts, BeforeBreadcrumbCallback, Breadcrumb Hint, clone + // TODO: Contexts + + /// Scope's event processor list + final List _eventProcessors = []; + + List get eventProcessors => + List.unmodifiable(_eventProcessors); final SentryOptions _options; Scope(this._options) : assert(_options != null, 'SentryOptions is required'); /// Adds a breadcrumb to the breadcrumbs queue - void addBreadcrumb(Breadcrumb breadcrumb) { + void addBreadcrumb(Breadcrumb breadcrumb, {dynamic hint}) { assert(breadcrumb != null, "Breadcrumb can't be null"); // bail out if maxBreadcrumbs is zero @@ -86,6 +74,17 @@ class Scope { return; } + // run before breadcrumb callback if set + if (_options.beforeBreadcrumbCallback != null) { + breadcrumb = _options.beforeBreadcrumbCallback(breadcrumb, hint); + + if (breadcrumb == null) { + _options.logger( + SentryLevel.info, 'Breadcrumb was dropped by beforeBreadcrumb'); + return; + } + } + // remove first item if list if full if (_breadcrumbs.length >= _options.maxBreadcrumbs && _breadcrumbs.isNotEmpty) { @@ -100,15 +99,23 @@ class Scope { _breadcrumbs.clear(); } + /// Adds an event processor + void addEventProcessor(EventProcessor eventProcessor) { + assert(eventProcessor != null, "EventProcessor can't be null"); + + _eventProcessors.add(eventProcessor); + } + /// Resets the Scope to its default state void clear() { clearBreadcrumbs(); - _level = null; - _transaction = null; - _user = null; + level = null; + transaction = null; + user = null; _fingerprint = null; _tags.clear(); _extra.clear(); + _eventProcessors.clear(); } /// Sets a tag to the Scope @@ -135,6 +142,7 @@ class Scope { /// Removes an extra from the Scope void removeExtra(String key) => _extra.remove(key); + /// Clones the current Scope Scope clone() { final clone = Scope(_options) ..user = user @@ -153,6 +161,10 @@ class Scope { clone.addBreadcrumb(breadcrumb); } + for (final eventProcessor in _eventProcessors) { + clone.addEventProcessor(eventProcessor); + } + return clone; } } diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart index d7fcea8edf..f539930405 100644 --- a/dart/test/scope_test.dart +++ b/dart/test/scope_test.dart @@ -48,6 +48,25 @@ void main() { expect(sut.breadcrumbs.last, breadcrumb); }); + test('Executes and drops $Breadcrumb', () { + final sut = fixture.getSut( + beforeBreadcrumbCallback: fixture.beforeBreadcrumbCallback, + ); + + final breadcrumb = Breadcrumb('test log', DateTime.utc(2019)); + sut.addBreadcrumb(breadcrumb); + + expect(sut.breadcrumbs.length, 0); + }); + + test('adds $EventProcessor', () { + final sut = fixture.getSut(); + + sut.addEventProcessor(fixture.processor); + + expect(sut.eventProcessors.last, fixture.processor); + }); + test('respects max $Breadcrumb', () { final maxBreadcrumbs = 2; final sut = fixture.getSut(maxBreadcrumbs: maxBreadcrumbs); @@ -149,6 +168,8 @@ void main() { sut.setTag('test', 'test'); sut.setExtra('test', 'test'); + sut.addEventProcessor(fixture.processor); + sut.clear(); expect(sut.breadcrumbs.length, 0); @@ -164,6 +185,8 @@ void main() { expect(sut.tags.length, 0); expect(sut.extra.length, 0); + + expect(sut.eventProcessors.length, 0); }); test('clones', () { @@ -175,13 +198,24 @@ void main() { expect(sut.tags, clone.tags); expect(sut.breadcrumbs, clone.breadcrumbs); expect(ListEquality().equals(sut.fingerprint, clone.fingerprint), true); + expect(ListEquality().equals(sut.eventProcessors, clone.eventProcessors), + true); }); } class Fixture { - Scope getSut({int maxBreadcrumbs = 100}) { + Scope getSut({ + int maxBreadcrumbs = 100, + BeforeBreadcrumbCallback beforeBreadcrumbCallback, + }) { final options = SentryOptions(); options.maxBreadcrumbs = maxBreadcrumbs; + options.beforeBreadcrumbCallback = beforeBreadcrumbCallback; return Scope(options); } + + SentryEvent processor(SentryEvent event, dynamic hint) => null; + + Breadcrumb beforeBreadcrumbCallback(Breadcrumb breadcrumb, dynamic hint) => + null; }