From 6b4d9aa1c23cb5778b5507a7263ed4807bdc4d20 Mon Sep 17 00:00:00 2001 From: rxlabz Date: Tue, 13 Oct 2020 13:21:09 +0200 Subject: [PATCH 01/13] feature : add a static SDK main entry withSentry.init(options), .captureEvent(...), .captureException(...) --- dart/example/event_example.dart | 73 +++++++++++++++++++++ dart/example/main.dart | 99 +++++++--------------------- dart/lib/sentry.dart | 1 + dart/lib/src/sentry.dart | 57 ++++++++++++++++ dart/lib/src/sentry_options.dart | 54 ++++++++++++++++ dart/pubspec.yaml | 2 +- dart/test/sentry_test.dart | 108 +++++++++++++++++++++++++++++++ 7 files changed, 316 insertions(+), 78 deletions(-) create mode 100644 dart/example/event_example.dart create mode 100644 dart/lib/src/sentry.dart create mode 100644 dart/lib/src/sentry_options.dart create mode 100644 dart/test/sentry_test.dart diff --git a/dart/example/event_example.dart b/dart/example/event_example.dart new file mode 100644 index 0000000000..b1115cf7ef --- /dev/null +++ b/dart/example/event_example.dart @@ -0,0 +1,73 @@ +import 'package:sentry/src/protocol.dart'; + +final event = Event( + loggerName: 'main', + serverName: 'server.dart', + release: '1.4.0-preview.1', + environment: 'Test', + message: Message(formatted: 'This is an example Dart event.'), + transaction: '/example/app', + level: SeverityLevel.warning, + tags: const {'project-id': '7371'}, + extra: const {'company-name': 'Dart Inc'}, + fingerprint: const ['example-dart'], + userContext: const User( + id: '800', + username: 'first-user', + email: 'first@user.lan', + ipAddress: '127.0.0.1', + extras: {'first-sign-in': '2020-01-01'}), + breadcrumbs: [ + Breadcrumb('UI Lifecycle', DateTime.now().toUtc(), + category: 'ui.lifecycle', + type: 'navigation', + data: {'screen': 'MainActivity', 'state': 'created'}, + level: SeverityLevel.info) + ], + contexts: Contexts( + operatingSystem: const OperatingSystem( + name: 'Android', + version: '5.0.2', + build: 'LRX22G.P900XXS0BPL2', + kernelVersion: + 'Linux version 3.4.39-5726670 (dpi@SWHC3807) (gcc version 4.8 (GCC) ) #1 SMP PREEMPT Thu Dec 1 19:42:39 KST 2016', + rooted: false), + runtimes: [const Runtime(name: 'ART', version: '5')], + app: App( + name: 'Example Dart App', + version: '1.42.0', + identifier: 'HGT-App-13', + build: '93785', + buildType: 'release', + deviceAppHash: '5afd3a6', + startTime: DateTime.now().toUtc()), + browser: const Browser(name: 'Firefox', version: '42.0.1'), + device: Device( + name: 'SM-P900', + family: 'SM-P900', + model: 'SM-P900 (LRX22G)', + modelId: 'LRX22G', + arch: 'armeabi-v7a', + batteryLevel: 99, + orientation: Orientation.landscape, + manufacturer: 'samsung', + brand: 'samsung', + screenResolution: '2560x1600', + screenDensity: 2.1, + screenDpi: 320, + online: true, + charging: true, + lowMemory: true, + simulator: false, + memorySize: 1500, + freeMemory: 200, + usableMemory: 4294967296, + storageSize: 4294967296, + freeStorage: 2147483648, + externalStorageSize: 8589934592, + externalFreeStorage: 2863311530, + bootTime: DateTime.now().toUtc(), + timezone: 'America/Toronto', + ), + ), +); diff --git a/dart/example/main.dart b/dart/example/main.dart index 14ee2dbb3d..6e83885fdc 100644 --- a/dart/example/main.dart +++ b/dart/example/main.dart @@ -5,7 +5,10 @@ import 'dart:async'; import 'dart:io'; -import 'package:sentry/sentry.dart'; +import 'package:sentry/src/sentry.dart'; +import 'package:sentry/src/sentry_options.dart'; + +import 'event_example.dart'; /// Sends a test exception report to Sentry.io using this Dart client. Future main(List rawArgs) async { @@ -16,18 +19,26 @@ Future main(List rawArgs) async { } final dsn = rawArgs.single; - final client = SentryClient(dsn: dsn); + Sentry.init(SentryOptions(dsn: dsn)); + + print('\nReporting a complete event example: '); // Sends a full Sentry event payload to show the different parts of the UI. - await captureCompleteExampleEvent(client); + final response = await Sentry.captureEvent(event); + + if (response.isSuccessful) { + print('SUCCESS\nid: ${response.eventId}'); + } else { + print('FAILURE: ${response.error}'); + } try { await foo(); } catch (error, stackTrace) { print('\nReporting the following stack trace: '); print(stackTrace); - final response = await client.captureException( - exception: error, + final response = await Sentry.captureException( + error, stackTrace: stackTrace, ); @@ -37,80 +48,13 @@ Future main(List rawArgs) async { print('FAILURE: ${response.error}'); } } finally { - await client.close(); + await Sentry.close(); } -} -Future captureCompleteExampleEvent(SentryClient client) async { - final event = Event( - loggerName: 'main', - serverName: 'server.dart', - release: '1.4.0-preview.1', - environment: 'Test', - message: Message(formatted: 'This is an example Dart event.'), - transaction: '/example/app', - level: SeverityLevel.warning, - tags: const {'project-id': '7371'}, - extra: const {'company-name': 'Dart Inc'}, - fingerprint: const ['example-dart'], - userContext: const User( - id: '800', - username: 'first-user', - email: 'first@user.lan', - ipAddress: '127.0.0.1', - extras: {'first-sign-in': '2020-01-01'}), - breadcrumbs: [ - Breadcrumb('UI Lifecycle', DateTime.now().toUtc(), - category: 'ui.lifecycle', - type: 'navigation', - data: {'screen': 'MainActivity', 'state': 'created'}, - level: SeverityLevel.info) - ], - contexts: Contexts( - operatingSystem: const OperatingSystem( - name: 'Android', - version: '5.0.2', - build: 'LRX22G.P900XXS0BPL2', - kernelVersion: - 'Linux version 3.4.39-5726670 (dpi@SWHC3807) (gcc version 4.8 (GCC) ) #1 SMP PREEMPT Thu Dec 1 19:42:39 KST 2016', - rooted: false), - runtimes: [const Runtime(name: 'ART', version: '5')], - app: App( - name: 'Example Dart App', - version: '1.42.0', - identifier: 'HGT-App-13', - build: '93785', - buildType: 'release', - deviceAppHash: '5afd3a6', - startTime: DateTime.now().toUtc()), - browser: const Browser(name: 'Firefox', version: '42.0.1'), - device: Device( - name: 'SM-P900', - family: 'SM-P900', - model: 'SM-P900 (LRX22G)', - modelId: 'LRX22G', - arch: 'armeabi-v7a', - batteryLevel: 99, - orientation: Orientation.landscape, - manufacturer: 'samsung', - brand: 'samsung', - screenResolution: '2560x1600', - screenDensity: 2.1, - screenDpi: 320, - online: true, - charging: true, - lowMemory: true, - simulator: false, - memorySize: 1500, - freeMemory: 200, - usableMemory: 4294967296, - storageSize: 4294967296, - freeStorage: 2147483648, - externalStorageSize: 8589934592, - externalFreeStorage: 2863311530, - bootTime: DateTime.now().toUtc(), - timezone: 'America/Toronto', - ))); + /* TODO(rxlabz) Sentry CaptureMessage(message, level) */ + +/*Future captureCompleteExampleEvent(SentryClient client) async { + final response = await client.captureEvent(event: event); @@ -120,6 +64,7 @@ Future captureCompleteExampleEvent(SentryClient client) async { } else { print('FAILURE: ${response.error}'); } +*/ } Future foo() async { diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index dcaa278d42..c4ddfab9ad 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -5,4 +5,5 @@ /// A pure Dart client for Sentry.io crash reporting. export 'src/client.dart'; export 'src/protocol.dart'; +export 'src/sentry.dart'; export 'src/version.dart'; diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart new file mode 100644 index 0000000000..beafd87762 --- /dev/null +++ b/dart/lib/src/sentry.dart @@ -0,0 +1,57 @@ +import 'package:meta/meta.dart'; + +import 'client.dart'; +import 'protocol.dart'; +import 'sentry_options.dart'; +import 'stack_trace.dart'; + +/// Sentry SDK main entry point +/// +class Sentry { + static SentryClient _client; + + Sentry._(); + + static void init(SentryOptions options) { + _client = SentryClient( + dsn: options.dsn, + environmentAttributes: options.environmentAttributes, + compressPayload: options.compressPayload, + httpClient: options.httpClient, + clock: options.clock, + uuidGenerator: options.uuidGenerator, + ); + } + + /// Initializes the SDK + static void initDns(String dns) => _client = SentryClient(dsn: dns); + + /// Reports an [event] to Sentry.io. + static Future captureEvent( + Event event, { + StackFrameFilter stackFrameFilter, + }) async { + return _client.captureEvent( + event: event, + stackFrameFilter: stackFrameFilter, + ); + } + + /// Reports the [exception] and optionally its [stackTrace] to Sentry.io. + static Future captureException( + dynamic error, { + dynamic stackTrace, + }) async { + return _client.captureException( + exception: error, + stackTrace: stackTrace, + ); + } + + /// Close the client SDK + static Future close() async => _client.close(); + + /// client injector only use for testing + @visibleForTesting + static void initClient(SentryClient client) => _client = client; +} diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart new file mode 100644 index 0000000000..cf4485e991 --- /dev/null +++ b/dart/lib/src/sentry_options.dart @@ -0,0 +1,54 @@ +import 'package:http/http.dart'; +import 'package:meta/meta.dart'; + +import 'protocol.dart'; +import 'utils.dart'; + +/// Sentry SDK options +class SentryOptions { + /// Default Log level if not specified Default is DEBUG + static final SeverityLevel defaultDiagnosticLevel = SeverityLevel.debug; + + /// The DSN tells the SDK where to send the events to. If this value is not provided, the SDK will + /// just not send any events. + final String dsn; + + /// Contains [Event] attributes that are automatically mixed into all events + /// captured through this client. + /// + /// This event is designed to contain static values that do not change from + /// event to event, such as local operating system version, the version of + /// Dart/Flutter SDK, etc. These attributes have lower precedence than those + /// supplied in the even passed to [capture]. + final Event environmentAttributes; + + /// If [compressPayload] is `true` the outgoing HTTP payloads are compressed + /// using gzip. Otherwise, the payloads are sent in plain UTF8-encoded JSON + /// text. If not specified, the compression is enabled by default. + final bool compressPayload; + + /// If [httpClient] is provided, it is used instead of the default client to + /// make HTTP calls to Sentry.io. This is useful in tests. + final Client httpClient; + + /// If [clock] is provided, it is used to get time instead of the system + /// clock. This is useful in tests. Should be an implementation of [ClockProvider]. + /// This parameter is dynamic to maintain backwards compatibility with + /// previous use of [Clock](https://pub.dartlang.org/documentation/quiver/latest/quiver.time/Clock-class.html) + /// from [`package:quiver`](https://pub.dartlang.org/packages/quiver). + final dynamic clock; + + /// If [uuidGenerator] is provided, it is used to generate the "event_id" + /// field instead of the built-in random UUID v4 generator. This is useful in + /// tests. + final UuidGenerator uuidGenerator; + + const SentryOptions({ + @required this.dsn, + this.environmentAttributes, + this.compressPayload, + this.httpClient, + this.clock, + this.uuidGenerator, + }); +} diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml index e688917675..f3710596d8 100644 --- a/dart/pubspec.yaml +++ b/dart/pubspec.yaml @@ -6,7 +6,7 @@ description: > homepage: https://github.com/getsentry/sentry-dart environment: - sdk: ^2.0.0 + sdk: ^2.1.0 dependencies: http: ^0.12.0 diff --git a/dart/test/sentry_test.dart b/dart/test/sentry_test.dart new file mode 100644 index 0000000000..fbbc7e30f9 --- /dev/null +++ b/dart/test/sentry_test.dart @@ -0,0 +1,108 @@ +import 'package:mockito/mockito.dart'; +import 'package:sentry/src/client.dart'; +import 'package:sentry/src/protocol.dart'; +import 'package:sentry/src/sentry.dart'; +import 'package:sentry/src/sentry_options.dart'; +import 'package:test/test.dart'; + +void main() { + group('Sentry.init', () { + SentryClient client; + + Exception anException; + + final dns = + 'https://cb0fad6f5d4e42ebb9c956cb0463edc9@o447951.ingest.sentry.io/5428562'; + + setUp(() { + Sentry.init(SentryOptions(dsn: dns)); + + client = MockSentryClient(); + Sentry.initClient(client); + }); + + test('should capture the event', () { + Sentry.captureEvent(event); + verify(client.captureEvent(event: event)).called(1); + }); + + test('should capture the exception', () { + Sentry.captureException(anException); + verify(client.captureException(exception: anException)).called(1); + }); + }); +} + +class MockSentryClient extends Mock implements SentryClient {} + +final event = Event( + loggerName: 'main', + serverName: 'server.dart', + release: '1.4.0-preview.1', + environment: 'Test', + message: Message(formatted: 'This is an example Dart event.'), + transaction: '/example/app', + level: SeverityLevel.warning, + tags: const {'project-id': '7371'}, + extra: const {'company-name': 'Dart Inc'}, + fingerprint: const ['example-dart'], + userContext: const User( + id: '800', + username: 'first-user', + email: 'first@user.lan', + ipAddress: '127.0.0.1', + extras: {'first-sign-in': '2020-01-01'}), + breadcrumbs: [ + Breadcrumb('UI Lifecycle', DateTime.now().toUtc(), + category: 'ui.lifecycle', + type: 'navigation', + data: {'screen': 'MainActivity', 'state': 'created'}, + level: SeverityLevel.info) + ], + contexts: Contexts( + operatingSystem: const OperatingSystem( + name: 'Android', + version: '5.0.2', + build: 'LRX22G.P900XXS0BPL2', + kernelVersion: + 'Linux version 3.4.39-5726670 (dpi@SWHC3807) (gcc version 4.8 (GCC) ) #1 SMP PREEMPT Thu Dec 1 19:42:39 KST 2016', + rooted: false), + runtimes: [const Runtime(name: 'ART', version: '5')], + app: App( + name: 'Example Dart App', + version: '1.42.0', + identifier: 'HGT-App-13', + build: '93785', + buildType: 'release', + deviceAppHash: '5afd3a6', + startTime: DateTime.now().toUtc()), + browser: const Browser(name: 'Firefox', version: '42.0.1'), + device: Device( + name: 'SM-P900', + family: 'SM-P900', + model: 'SM-P900 (LRX22G)', + modelId: 'LRX22G', + arch: 'armeabi-v7a', + batteryLevel: 99, + orientation: Orientation.landscape, + manufacturer: 'samsung', + brand: 'samsung', + screenResolution: '2560x1600', + screenDensity: 2.1, + screenDpi: 320, + online: true, + charging: true, + lowMemory: true, + simulator: false, + memorySize: 1500, + freeMemory: 200, + usableMemory: 4294967296, + storageSize: 4294967296, + freeStorage: 2147483648, + externalStorageSize: 8589934592, + externalFreeStorage: 2863311530, + bootTime: DateTime.now().toUtc(), + timezone: 'America/Toronto', + ), + ), +); From f0913868ea40a96ba8c3d06621e097bd980ec19c Mon Sep 17 00:00:00 2001 From: rxlabz Date: Tue, 13 Oct 2020 13:50:44 +0200 Subject: [PATCH 02/13] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf86df0b03..e82267b466 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - 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 +- new static API : Sentry.init(), Sentry.captureEvent() #108 # `package:sentry` changelog From 43109b3db5bca151348383751352f078b67c2278 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 13 Oct 2020 13:56:11 +0200 Subject: [PATCH 03/13] feat: add Scope class --- dart/lib/sentry.dart | 2 + dart/lib/src/scope.dart | 80 +++++++++++ dart/lib/src/sentry_options.dart | 5 + dart/pubspec.yaml | 2 +- dart/test/scope_test.dart | 238 +++++++++++++++++++++++++++++++ 5 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 dart/lib/src/scope.dart create mode 100644 dart/lib/src/sentry_options.dart create mode 100644 dart/test/scope_test.dart diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index dcaa278d42..d81860c038 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -6,3 +6,5 @@ export 'src/client.dart'; export 'src/protocol.dart'; export 'src/version.dart'; +export 'src/scope.dart'; +export 'src/sentry_options.dart'; diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart new file mode 100644 index 0000000000..b7a9e7a7ee --- /dev/null +++ b/dart/lib/src/scope.dart @@ -0,0 +1,80 @@ +import 'dart:collection'; + +import 'protocol.dart'; +import 'sentry_options.dart'; + +/// Scope data to be sent with the event +class Scope { + /// How important this event is. + SeverityLevel level; + + /// The name of the transaction which generated this event, + /// for example, the route name: `"/users//"`. + String transaction; + + /// Information about the current user. + User user; + + /// Used to deduplicate events by grouping ones with the same fingerprint + /// together. + /// + /// Example: + /// + /// // A completely custom fingerprint: + /// var custom = ['foo', 'bar', 'baz']; + List fingerprint; + + /// List of breadcrumbs for this scope. + /// + /// See also: + /// * https://docs.sentry.io/enriching-error-data/breadcrumbs/?platform=javascript + final Queue _breadcrumbs = Queue(); + + /// Unmodifiable List of breadcrumbs + List get breadcrumbs => List.unmodifiable(_breadcrumbs); + + /// Name/value pairs that events can be searched by. + final Map tags = {}; + + /// Arbitrary name/value pairs attached to the scope. + /// + /// Sentry.io docs do not talk about restrictions on the values, other than + /// they must be JSON-serializable. + final Map extra = {}; + + // TODO: eventProcessors, Contexts, BeforeBreadcrumbCallback, Breadcrumb hint, clome + + final SentryOptions _options; + + Scope(this._options) : assert(_options != null, 'SentryOptions is required'); + + /// Adds a breadcrumb to the breadcrumbs queue + void addBreadcrumb(Breadcrumb breadcrumb) { + assert(breadcrumb != null, "Breadcrumb can't be null"); + + if (_breadcrumbs.length >= _options.maxBreadcrumbs && + _breadcrumbs.isNotEmpty) { + _breadcrumbs.removeFirst(); + } + if (_options.maxBreadcrumbs == 0) { + return; + } + _breadcrumbs.add(breadcrumb); + } + + /// Clear all the breadcrumbs + void clearBreadcrumbs() { + _breadcrumbs.clear(); + } + + /// Resets the Scope to its default state + void clear() { + clearBreadcrumbs(); + level = null; + transaction = null; + user = null; + fingerprint = null; + tags.clear(); + extra.clear(); + } +} diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart new file mode 100644 index 0000000000..cde1d36fe5 --- /dev/null +++ b/dart/lib/src/sentry_options.dart @@ -0,0 +1,5 @@ +/// Sentry SDK options +class SentryOptions { + /// This variable controls the total amount of breadcrumbs that should be captured Default is 100 + int maxBreadcrumbs = 100; +} diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml index e688917675..34e82cf850 100644 --- a/dart/pubspec.yaml +++ b/dart/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: uuid: ^2.0.0 dev_dependencies: - mockito: ^4.1.2 + mockito: ^4.1.1 pedantic: ^1.9.2 test: ^1.15.4 yaml: ^2.2.1 diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart new file mode 100644 index 0000000000..c80f210351 --- /dev/null +++ b/dart/test/scope_test.dart @@ -0,0 +1,238 @@ +import 'package:sentry/sentry.dart'; +import 'package:test/test.dart'; + +void main() { + final fixture = Fixture(); + + test('sets $SeverityLevel', () { + final sut = fixture.getSut(); + + sut.level = SeverityLevel.debug; + + expect( + sut.level, + SeverityLevel.debug, + ); + }); + + test('sets transaction', () { + final sut = fixture.getSut(); + + sut.transaction = 'test'; + + expect( + sut.transaction, + 'test', + ); + }); + + test('sets $User', () { + final sut = fixture.getSut(); + + final user = User(id: 'test'); + sut.user = user; + + expect( + sut.user, + user, + ); + }); + + test('sets fingerprint', () { + final sut = fixture.getSut(); + + final fingerprints = ['test']; + sut.fingerprint = fingerprints; + + expect( + sut.fingerprint, + fingerprints, + ); + }); + + test('adds $Breadcrumb', () { + final sut = fixture.getSut(); + + final breadcrumb = Breadcrumb('test log', DateTime.utc(2019)); + sut.addBreadcrumb(breadcrumb); + + expect( + sut.breadcrumbs.last, + breadcrumb, + ); + }); + + test('respects max $Breadcrumb', () { + final maxBreadcrumbs = 2; + final sut = fixture.getSut(maxBreadcrumbs: maxBreadcrumbs); + + final breadcrumb1 = Breadcrumb('test log', DateTime.utc(2019)); + final breadcrumb2 = Breadcrumb('test log', DateTime.utc(2019)); + final breadcrumb3 = Breadcrumb('test log', DateTime.utc(2019)); + sut.addBreadcrumb(breadcrumb1); + sut.addBreadcrumb(breadcrumb2); + sut.addBreadcrumb(breadcrumb3); + + expect( + sut.breadcrumbs.length, + maxBreadcrumbs, + ); + }); + + test('rotates $Breadcrumb', () { + final sut = fixture.getSut(maxBreadcrumbs: 2); + + final breadcrumb1 = Breadcrumb('test log', DateTime.utc(2019)); + final breadcrumb2 = Breadcrumb('test log', DateTime.utc(2019)); + final breadcrumb3 = Breadcrumb('test log', DateTime.utc(2019)); + sut.addBreadcrumb(breadcrumb1); + sut.addBreadcrumb(breadcrumb2); + sut.addBreadcrumb(breadcrumb3); + + expect( + sut.breadcrumbs.first, + breadcrumb2, + ); + + expect( + sut.breadcrumbs.last, + breadcrumb3, + ); + }); + + test('empty $Breadcrumb list', () { + final maxBreadcrumbs = 0; + final sut = fixture.getSut(maxBreadcrumbs: maxBreadcrumbs); + + final breadcrumb1 = Breadcrumb('test log', DateTime.utc(2019)); + sut.addBreadcrumb(breadcrumb1); + + expect( + sut.breadcrumbs.length, + maxBreadcrumbs, + ); + }); + + test('clears $Breadcrumb list', () { + final sut = fixture.getSut(); + + final breadcrumb1 = Breadcrumb('test log', DateTime.utc(2019)); + sut.addBreadcrumb(breadcrumb1); + sut.clear(); + + expect( + sut.breadcrumbs.length, + 0, + ); + }); + + test('sets tag', () { + final sut = fixture.getSut(); + + sut.tags['test'] = 'test'; + + expect( + sut.tags['test'], + 'test', + ); + }); + + test('removes tag', () { + final sut = fixture.getSut(); + + sut.tags['test'] = 'test'; + sut.tags.remove('test'); + + expect( + sut.tags['test'], + null, + ); + }); + + test('sets extra', () { + final sut = fixture.getSut(); + + sut.extra['test'] = 'test'; + + expect( + sut.extra['test'], + 'test', + ); + }); + + test('removes extra', () { + final sut = fixture.getSut(); + + sut.extra['test'] = 'test'; + sut.extra.remove('test'); + + expect( + sut.extra['test'], + null, + ); + }); + + test('clears $Scope', () { + final sut = fixture.getSut(); + + final breadcrumb1 = Breadcrumb('test log', DateTime.utc(2019)); + sut.addBreadcrumb(breadcrumb1); + + sut.level = SeverityLevel.debug; + sut.transaction = 'test'; + + final user = User(id: 'test'); + sut.user = user; + + final fingerprints = ['test']; + sut.fingerprint = fingerprints; + + sut.tags['test'] = 'test'; + sut.extra['test'] = 'test'; + + sut.clear(); + + expect( + sut.breadcrumbs.length, + 0, + ); + + expect( + sut.level, + null, + ); + + expect( + sut.transaction, + null, + ); + + expect( + sut.user, + null, + ); + + expect( + sut.fingerprint, + null, + ); + + expect( + sut.tags.length, + 0, + ); + + expect( + sut.extra.length, + 0, + ); + }); +} + +class Fixture { + Scope getSut({int maxBreadcrumbs = 100}) { + final options = SentryOptions(); + options.maxBreadcrumbs = maxBreadcrumbs; + return Scope(options); + } +} From 03405a04ef256cb61de54ed9aa359811ef989f57 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Tue, 13 Oct 2020 14:34:10 +0200 Subject: [PATCH 04/13] add comments --- dart/lib/src/scope.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart index b7a9e7a7ee..f0b3956ce7 100644 --- a/dart/lib/src/scope.dart +++ b/dart/lib/src/scope.dart @@ -42,7 +42,7 @@ class Scope { /// they must be JSON-serializable. final Map extra = {}; - // TODO: eventProcessors, Contexts, BeforeBreadcrumbCallback, Breadcrumb hint, clome + // TODO: eventProcessors, Contexts, BeforeBreadcrumbCallback, Breadcrumb hint, clone final SentryOptions _options; @@ -52,13 +52,17 @@ class Scope { void addBreadcrumb(Breadcrumb breadcrumb) { assert(breadcrumb != null, "Breadcrumb can't be null"); + // bail out if maxBreadcrumbs is zero + if (_options.maxBreadcrumbs == 0) { + return; + } + + // remove first item if list if full if (_breadcrumbs.length >= _options.maxBreadcrumbs && _breadcrumbs.isNotEmpty) { _breadcrumbs.removeFirst(); } - if (_options.maxBreadcrumbs == 0) { - return; - } + _breadcrumbs.add(breadcrumb); } From 870724aaafd911ad074207cf03aaecca187d3a56 Mon Sep 17 00:00:00 2001 From: rxlabz Date: Tue, 13 Oct 2020 16:17:28 +0200 Subject: [PATCH 05/13] remove a useless method --- dart/lib/src/sentry.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index beafd87762..390de1194e 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -23,9 +23,6 @@ class Sentry { ); } - /// Initializes the SDK - static void initDns(String dns) => _client = SentryClient(dsn: dns); - /// Reports an [event] to Sentry.io. static Future captureEvent( Event event, { From 898b45107e3c61b35e18663244589d7adb225f99 Mon Sep 17 00:00:00 2001 From: rxlabz Date: Tue, 13 Oct 2020 16:18:25 +0200 Subject: [PATCH 06/13] export `sentry_options.dart` --- dart/example/main.dart | 3 +-- dart/lib/sentry.dart | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dart/example/main.dart b/dart/example/main.dart index 6e83885fdc..c9ca925ad3 100644 --- a/dart/example/main.dart +++ b/dart/example/main.dart @@ -5,8 +5,7 @@ import 'dart:async'; import 'dart:io'; -import 'package:sentry/src/sentry.dart'; -import 'package:sentry/src/sentry_options.dart'; +import 'package:sentry/sentry.dart'; import 'event_example.dart'; diff --git a/dart/lib/sentry.dart b/dart/lib/sentry.dart index c4ddfab9ad..b6aeebfdf5 100644 --- a/dart/lib/sentry.dart +++ b/dart/lib/sentry.dart @@ -6,4 +6,5 @@ export 'src/client.dart'; export 'src/protocol.dart'; export 'src/sentry.dart'; +export 'src/sentry_options.dart'; export 'src/version.dart'; From d9652dad77c0875f85e059c22cab8092c26f9cc8 Mon Sep 17 00:00:00 2001 From: rxlabz Date: Tue, 13 Oct 2020 17:01:48 +0200 Subject: [PATCH 07/13] add OptionsConfiguration --- dart/example/main.dart | 26 ++++++++++++-------------- dart/lib/src/sentry.dart | 21 +++++++++++---------- dart/lib/src/sentry_options.dart | 17 ++++++++--------- dart/pubspec.yaml | 2 +- dart/test/sentry_test.dart | 20 ++++++++++++++++++-- 5 files changed, 50 insertions(+), 36 deletions(-) diff --git a/dart/example/main.dart b/dart/example/main.dart index c9ca925ad3..6ba08a036c 100644 --- a/dart/example/main.dart +++ b/dart/example/main.dart @@ -18,7 +18,7 @@ Future main(List rawArgs) async { } final dsn = rawArgs.single; - Sentry.init(SentryOptions(dsn: dsn)); + Sentry.init(Options(dsn: dsn)); print('\nReporting a complete event example: '); @@ -51,19 +51,6 @@ Future main(List rawArgs) async { } /* TODO(rxlabz) Sentry CaptureMessage(message, level) */ - -/*Future captureCompleteExampleEvent(SentryClient client) async { - - - final response = await client.captureEvent(event: event); - - print('\nReporting a complete event example: '); - if (response.isSuccessful) { - print('SUCCESS\nid: ${response.eventId}'); - } else { - print('FAILURE: ${response.error}'); - } -*/ } Future foo() async { @@ -77,3 +64,14 @@ Future bar() async { Future baz() async { throw StateError('This is a test error'); } + +class Options implements OptionsConfiguration { + final String dsn; + + Options({this.dsn}); + + @override + void configure(SentryOptions options) { + options.dsn = dsn; + } +} diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index 390de1194e..6d52affb18 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -3,7 +3,6 @@ import 'package:meta/meta.dart'; import 'client.dart'; import 'protocol.dart'; import 'sentry_options.dart'; -import 'stack_trace.dart'; /// Sentry SDK main entry point /// @@ -12,7 +11,9 @@ class Sentry { Sentry._(); - static void init(SentryOptions options) { + static void init(OptionsConfiguration optionsConfiguration) { + final options = SentryOptions(); + optionsConfiguration.configure(options); _client = SentryClient( dsn: options.dsn, environmentAttributes: options.environmentAttributes, @@ -24,14 +25,8 @@ class Sentry { } /// Reports an [event] to Sentry.io. - static Future captureEvent( - Event event, { - StackFrameFilter stackFrameFilter, - }) async { - return _client.captureEvent( - event: event, - stackFrameFilter: stackFrameFilter, - ); + static Future captureEvent(Event event) async { + return _client.captureEvent(event: event); } /// Reports the [exception] and optionally its [stackTrace] to Sentry.io. @@ -52,3 +47,9 @@ class Sentry { @visibleForTesting static void initClient(SentryClient client) => _client = client; } + +/// Configuration options callback +abstract class OptionsConfiguration { + ///configure the options + void configure(T options); +} diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index cf4485e991..76e5760ecb 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -1,5 +1,4 @@ import 'package:http/http.dart'; -import 'package:meta/meta.dart'; import 'protocol.dart'; import 'utils.dart'; @@ -11,7 +10,7 @@ class SentryOptions { /// The DSN tells the SDK where to send the events to. If this value is not provided, the SDK will /// just not send any events. - final String dsn; + String dsn; /// Contains [Event] attributes that are automatically mixed into all events /// captured through this client. @@ -20,31 +19,31 @@ class SentryOptions { /// event to event, such as local operating system version, the version of /// Dart/Flutter SDK, etc. These attributes have lower precedence than those /// supplied in the even passed to [capture]. - final Event environmentAttributes; + Event environmentAttributes; /// If [compressPayload] is `true` the outgoing HTTP payloads are compressed /// using gzip. Otherwise, the payloads are sent in plain UTF8-encoded JSON /// text. If not specified, the compression is enabled by default. - final bool compressPayload; + bool compressPayload; /// If [httpClient] is provided, it is used instead of the default client to /// make HTTP calls to Sentry.io. This is useful in tests. - final Client httpClient; + Client httpClient; /// If [clock] is provided, it is used to get time instead of the system /// clock. This is useful in tests. Should be an implementation of [ClockProvider]. /// This parameter is dynamic to maintain backwards compatibility with /// previous use of [Clock](https://pub.dartlang.org/documentation/quiver/latest/quiver.time/Clock-class.html) /// from [`package:quiver`](https://pub.dartlang.org/packages/quiver). - final dynamic clock; + dynamic clock; /// If [uuidGenerator] is provided, it is used to generate the "event_id" /// field instead of the built-in random UUID v4 generator. This is useful in /// tests. - final UuidGenerator uuidGenerator; + UuidGenerator uuidGenerator; - const SentryOptions({ - @required this.dsn, + SentryOptions({ + this.dsn, this.environmentAttributes, this.compressPayload, this.httpClient, diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml index f3710596d8..e688917675 100644 --- a/dart/pubspec.yaml +++ b/dart/pubspec.yaml @@ -6,7 +6,7 @@ description: > homepage: https://github.com/getsentry/sentry-dart environment: - sdk: ^2.1.0 + sdk: ^2.0.0 dependencies: http: ^0.12.0 diff --git a/dart/test/sentry_test.dart b/dart/test/sentry_test.dart index fbbc7e30f9..da2e559646 100644 --- a/dart/test/sentry_test.dart +++ b/dart/test/sentry_test.dart @@ -6,7 +6,7 @@ import 'package:sentry/src/sentry_options.dart'; import 'package:test/test.dart'; void main() { - group('Sentry.init', () { + group('Sentry static entry', () { SentryClient client; Exception anException; @@ -15,7 +15,7 @@ void main() { 'https://cb0fad6f5d4e42ebb9c956cb0463edc9@o447951.ingest.sentry.io/5428562'; setUp(() { - Sentry.init(SentryOptions(dsn: dns)); + Sentry.init(Options(dsn: dns)); client = MockSentryClient(); Sentry.initClient(client); @@ -26,6 +26,11 @@ void main() { verify(client.captureEvent(event: event)).called(1); }); + test('should capture the event', () { + Sentry.captureEvent(event); + verify(client.captureEvent(event: event)).called(1); + }); + test('should capture the exception', () { Sentry.captureException(anException); verify(client.captureException(exception: anException)).called(1); @@ -35,6 +40,17 @@ void main() { class MockSentryClient extends Mock implements SentryClient {} +class Options implements OptionsConfiguration { + final String dsn; + + Options({this.dsn}); + + @override + void configure(SentryOptions options) { + options.dsn = dsn; + } +} + final event = Event( loggerName: 'main', serverName: 'server.dart', From 408fa5abf78e23e48590aaa57eee742c06e4e033 Mon Sep 17 00:00:00 2001 From: rxlabz Date: Tue, 13 Oct 2020 17:10:00 +0200 Subject: [PATCH 08/13] rename `environmentAttributes` to `environment` --- dart/lib/src/client.dart | 4 ++-- dart/lib/src/sentry.dart | 4 +++- dart/lib/src/sentry_options.dart | 4 ++-- dart/test/sentry_test.dart | 3 +-- dart/test/test_utils.dart | 8 ++++---- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/dart/lib/src/client.dart b/dart/lib/src/client.dart index 08cc0f8bc8..d7cfc8d728 100644 --- a/dart/lib/src/client.dart +++ b/dart/lib/src/client.dart @@ -23,7 +23,7 @@ abstract class SentryClient { /// `dart:html` is available, otherwise it will throw an unsupported error. factory SentryClient({ @required String dsn, - Event environmentAttributes, + Event environment, bool compressPayload, Client httpClient, dynamic clock, @@ -31,7 +31,7 @@ abstract class SentryClient { }) => createSentryClient( dsn: dsn, - environmentAttributes: environmentAttributes, + environmentAttributes: environment, httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index 6d52affb18..0c4fb8e90e 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:meta/meta.dart'; import 'client.dart'; @@ -16,7 +18,7 @@ class Sentry { optionsConfiguration.configure(options); _client = SentryClient( dsn: options.dsn, - environmentAttributes: options.environmentAttributes, + environment: options.environment, compressPayload: options.compressPayload, httpClient: options.httpClient, clock: options.clock, diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index 76e5760ecb..f379a3f1ef 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -19,7 +19,7 @@ class SentryOptions { /// event to event, such as local operating system version, the version of /// Dart/Flutter SDK, etc. These attributes have lower precedence than those /// supplied in the even passed to [capture]. - Event environmentAttributes; + Event environment; /// If [compressPayload] is `true` the outgoing HTTP payloads are compressed /// using gzip. Otherwise, the payloads are sent in plain UTF8-encoded JSON @@ -44,7 +44,7 @@ class SentryOptions { SentryOptions({ this.dsn, - this.environmentAttributes, + this.environment, this.compressPayload, this.httpClient, this.clock, diff --git a/dart/test/sentry_test.dart b/dart/test/sentry_test.dart index da2e559646..d0780dd83f 100644 --- a/dart/test/sentry_test.dart +++ b/dart/test/sentry_test.dart @@ -11,8 +11,7 @@ void main() { Exception anException; - final dns = - 'https://cb0fad6f5d4e42ebb9c956cb0463edc9@o447951.ingest.sentry.io/5428562'; + final dns = 'https://abc@def.ingest.sentry.io/1234567'; setUp(() { Sentry.init(Options(dsn: dns)); diff --git a/dart/test/test_utils.dart b/dart/test/test_utils.dart index 9eb48b6e07..531b82f7ce 100644 --- a/dart/test/test_utils.dart +++ b/dart/test/test_utils.dart @@ -74,7 +74,7 @@ Future testCaptureException( clock: fakeClockProvider, uuidGenerator: () => 'X' * 32, compressPayload: compressPayload, - environmentAttributes: const Event( + environment: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging', @@ -233,7 +233,7 @@ void runTest({Codec, List> gzip, bool isWeb = false}) { clock: fakeClockProvider, compressPayload: false, uuidGenerator: () => 'X' * 32, - environmentAttributes: const Event( + environment: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging', @@ -290,7 +290,7 @@ void runTest({Codec, List> gzip, bool isWeb = false}) { clock: fakeClockProvider, uuidGenerator: () => 'X' * 32, compressPayload: false, - environmentAttributes: const Event( + environment: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging', @@ -347,7 +347,7 @@ void runTest({Codec, List> gzip, bool isWeb = false}) { clock: fakeClockProvider, uuidGenerator: () => 'X' * 32, compressPayload: false, - environmentAttributes: const Event( + environment: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging', From b971db2f2750e98d231f72ed2d884f2441f30194 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Wed, 14 Oct 2020 13:14:38 +0200 Subject: [PATCH 09/13] added getters and setters --- dart/lib/src/scope.dart | 81 +++++++++++++++++++---- dart/test/scope_test.dart | 133 ++++++++++---------------------------- 2 files changed, 103 insertions(+), 111 deletions(-) diff --git a/dart/lib/src/scope.dart b/dart/lib/src/scope.dart index f0b3956ce7..63e1c85ec8 100644 --- a/dart/lib/src/scope.dart +++ b/dart/lib/src/scope.dart @@ -6,14 +6,32 @@ import 'sentry_options.dart'; /// Scope data to be sent with the event class Scope { /// How important this event is. - SeverityLevel level; + SeverityLevel _level; + + SeverityLevel get level => _level; + + set level(SeverityLevel level) { + _level = level; + } /// The name of the transaction which generated this event, /// for example, the route name: `"/users//"`. - String transaction; + String _transaction; + + String get transaction => _transaction; + + set transaction(String transaction) { + _transaction = transaction; + } /// Information about the current user. - User user; + User _user; + + User get user => _user; + + set user(User user) { + _user = user; + } /// Used to deduplicate events by grouping ones with the same fingerprint /// together. @@ -22,7 +40,14 @@ class Scope { /// /// // A completely custom fingerprint: /// var custom = ['foo', 'bar', 'baz']; - List fingerprint; + List _fingerprint; + + List get fingerprint => + _fingerprint != null ? List.unmodifiable(_fingerprint) : null; + + set fingerprint(List fingerprint) { + _fingerprint = fingerprint; + } /// List of breadcrumbs for this scope. /// @@ -34,15 +59,19 @@ class Scope { List get breadcrumbs => List.unmodifiable(_breadcrumbs); /// Name/value pairs that events can be searched by. - final Map tags = {}; + final Map _tags = {}; + + Map get tags => Map.unmodifiable(_tags); /// Arbitrary name/value pairs attached to the scope. /// /// Sentry.io docs do not talk about restrictions on the values, other than /// they must be JSON-serializable. - final Map extra = {}; + final Map _extra = {}; + + Map get extra => Map.unmodifiable(_extra); - // TODO: eventProcessors, Contexts, BeforeBreadcrumbCallback, Breadcrumb hint, clone + // TODO: EventProcessors, Contexts, BeforeBreadcrumbCallback, Breadcrumb Hint, clone final SentryOptions _options; @@ -74,11 +103,37 @@ class Scope { /// Resets the Scope to its default state void clear() { clearBreadcrumbs(); - level = null; - transaction = null; - user = null; - fingerprint = null; - tags.clear(); - extra.clear(); + _level = null; + _transaction = null; + _user = null; + _fingerprint = null; + _tags.clear(); + _extra.clear(); + } + + /// Sets a tag to the Scope + void setTag(String key, String value) { + assert(key != null, "Key can't be null"); + assert(value != null, "Key can't be null"); + + _tags[key] = value; + } + + /// Removes a tag from the Scope + void removeTag(String key) { + _tags.remove(key); + } + + /// Sets an extra to the Scope + void setExtra(String key, dynamic value) { + assert(key != null, "Key can't be null"); + assert(value != null, "Value can't be null"); + + _extra[key] = value; + } + + /// Removes an extra from the Scope + void removeExtra(String key) { + _extra.remove(key); } } diff --git a/dart/test/scope_test.dart b/dart/test/scope_test.dart index c80f210351..2139b3d772 100644 --- a/dart/test/scope_test.dart +++ b/dart/test/scope_test.dart @@ -9,10 +9,7 @@ void main() { sut.level = SeverityLevel.debug; - expect( - sut.level, - SeverityLevel.debug, - ); + expect(sut.level, SeverityLevel.debug); }); test('sets transaction', () { @@ -20,10 +17,7 @@ void main() { sut.transaction = 'test'; - expect( - sut.transaction, - 'test', - ); + expect(sut.transaction, 'test'); }); test('sets $User', () { @@ -32,10 +26,7 @@ void main() { final user = User(id: 'test'); sut.user = user; - expect( - sut.user, - user, - ); + expect(sut.user, user); }); test('sets fingerprint', () { @@ -44,10 +35,7 @@ void main() { final fingerprints = ['test']; sut.fingerprint = fingerprints; - expect( - sut.fingerprint, - fingerprints, - ); + expect(sut.fingerprint, fingerprints); }); test('adds $Breadcrumb', () { @@ -56,10 +44,7 @@ void main() { final breadcrumb = Breadcrumb('test log', DateTime.utc(2019)); sut.addBreadcrumb(breadcrumb); - expect( - sut.breadcrumbs.last, - breadcrumb, - ); + expect(sut.breadcrumbs.last, breadcrumb); }); test('respects max $Breadcrumb', () { @@ -73,10 +58,7 @@ void main() { sut.addBreadcrumb(breadcrumb2); sut.addBreadcrumb(breadcrumb3); - expect( - sut.breadcrumbs.length, - maxBreadcrumbs, - ); + expect(sut.breadcrumbs.length, maxBreadcrumbs); }); test('rotates $Breadcrumb', () { @@ -89,15 +71,9 @@ void main() { sut.addBreadcrumb(breadcrumb2); sut.addBreadcrumb(breadcrumb3); - expect( - sut.breadcrumbs.first, - breadcrumb2, - ); + expect(sut.breadcrumbs.first, breadcrumb2); - expect( - sut.breadcrumbs.last, - breadcrumb3, - ); + expect(sut.breadcrumbs.last, breadcrumb3); }); test('empty $Breadcrumb list', () { @@ -107,10 +83,7 @@ void main() { final breadcrumb1 = Breadcrumb('test log', DateTime.utc(2019)); sut.addBreadcrumb(breadcrumb1); - expect( - sut.breadcrumbs.length, - maxBreadcrumbs, - ); + expect(sut.breadcrumbs.length, maxBreadcrumbs); }); test('clears $Breadcrumb list', () { @@ -120,56 +93,41 @@ void main() { sut.addBreadcrumb(breadcrumb1); sut.clear(); - expect( - sut.breadcrumbs.length, - 0, - ); + expect(sut.breadcrumbs.length, 0); }); test('sets tag', () { final sut = fixture.getSut(); - sut.tags['test'] = 'test'; + sut.setTag('test', 'test'); - expect( - sut.tags['test'], - 'test', - ); + expect(sut.tags['test'], 'test'); }); test('removes tag', () { final sut = fixture.getSut(); - sut.tags['test'] = 'test'; - sut.tags.remove('test'); + sut.setTag('test', 'test'); + sut.removeTag('test'); - expect( - sut.tags['test'], - null, - ); + expect(sut.tags['test'], null); }); test('sets extra', () { final sut = fixture.getSut(); - sut.extra['test'] = 'test'; + sut.setExtra('test', 'test'); - expect( - sut.extra['test'], - 'test', - ); + expect(sut.extra['test'], 'test'); }); test('removes extra', () { final sut = fixture.getSut(); - sut.extra['test'] = 'test'; - sut.extra.remove('test'); + sut.setExtra('test', 'test'); + sut.removeExtra('test'); - expect( - sut.extra['test'], - null, - ); + expect(sut.extra['test'], null); }); test('clears $Scope', () { @@ -187,45 +145,24 @@ void main() { final fingerprints = ['test']; sut.fingerprint = fingerprints; - sut.tags['test'] = 'test'; - sut.extra['test'] = 'test'; + sut.setTag('test', 'test'); + sut.setExtra('test', 'test'); sut.clear(); - expect( - sut.breadcrumbs.length, - 0, - ); - - expect( - sut.level, - null, - ); - - expect( - sut.transaction, - null, - ); - - expect( - sut.user, - null, - ); - - expect( - sut.fingerprint, - null, - ); - - expect( - sut.tags.length, - 0, - ); - - expect( - sut.extra.length, - 0, - ); + expect(sut.breadcrumbs.length, 0); + + expect(sut.level, null); + + expect(sut.transaction, null); + + expect(sut.user, null); + + expect(sut.fingerprint, null); + + expect(sut.tags.length, 0); + + expect(sut.extra.length, 0); }); } From 6459069ad58926558137713e2b52378db6b7ec06 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Wed, 14 Oct 2020 13:19:22 +0200 Subject: [PATCH 10/13] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf86df0b03..b9692e13ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - 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 +- Added Scope and Breadcrumb ring buffer #109 # `package:sentry` changelog From cf5cd5089f4acf0cd2b80b2b89567bd4805d831b Mon Sep 17 00:00:00 2001 From: rxlabz Date: Wed, 14 Oct 2020 14:06:02 +0200 Subject: [PATCH 11/13] turn OptionsConfiguration to a typedef --- dart/example/main.dart | 13 +------------ dart/lib/src/sentry.dart | 13 +++++-------- dart/test/sentry_test.dart | 18 ++---------------- 3 files changed, 8 insertions(+), 36 deletions(-) diff --git a/dart/example/main.dart b/dart/example/main.dart index 6ba08a036c..ff859af407 100644 --- a/dart/example/main.dart +++ b/dart/example/main.dart @@ -18,7 +18,7 @@ Future main(List rawArgs) async { } final dsn = rawArgs.single; - Sentry.init(Options(dsn: dsn)); + Sentry.init((options) => options.dsn = dsn); print('\nReporting a complete event example: '); @@ -64,14 +64,3 @@ Future bar() async { Future baz() async { throw StateError('This is a test error'); } - -class Options implements OptionsConfiguration { - final String dsn; - - Options({this.dsn}); - - @override - void configure(SentryOptions options) { - options.dsn = dsn; - } -} diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index 0c4fb8e90e..c695778e9b 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -6,6 +6,9 @@ import 'client.dart'; import 'protocol.dart'; import 'sentry_options.dart'; +/// Configuration options callback +typedef OptionsConfiguration = void Function(SentryOptions); + /// Sentry SDK main entry point /// class Sentry { @@ -13,9 +16,9 @@ class Sentry { Sentry._(); - static void init(OptionsConfiguration optionsConfiguration) { + static void init(OptionsConfiguration optionsConfiguration) { final options = SentryOptions(); - optionsConfiguration.configure(options); + optionsConfiguration(options); _client = SentryClient( dsn: options.dsn, environment: options.environment, @@ -49,9 +52,3 @@ class Sentry { @visibleForTesting static void initClient(SentryClient client) => _client = client; } - -/// Configuration options callback -abstract class OptionsConfiguration { - ///configure the options - void configure(T options); -} diff --git a/dart/test/sentry_test.dart b/dart/test/sentry_test.dart index d0780dd83f..8fa961361a 100644 --- a/dart/test/sentry_test.dart +++ b/dart/test/sentry_test.dart @@ -1,8 +1,5 @@ import 'package:mockito/mockito.dart'; -import 'package:sentry/src/client.dart'; -import 'package:sentry/src/protocol.dart'; -import 'package:sentry/src/sentry.dart'; -import 'package:sentry/src/sentry_options.dart'; +import 'package:sentry/sentry.dart'; import 'package:test/test.dart'; void main() { @@ -14,7 +11,7 @@ void main() { final dns = 'https://abc@def.ingest.sentry.io/1234567'; setUp(() { - Sentry.init(Options(dsn: dns)); + Sentry.init((options) => options.dsn = dns); client = MockSentryClient(); Sentry.initClient(client); @@ -39,17 +36,6 @@ void main() { class MockSentryClient extends Mock implements SentryClient {} -class Options implements OptionsConfiguration { - final String dsn; - - Options({this.dsn}); - - @override - void configure(SentryOptions options) { - options.dsn = dsn; - } -} - final event = Event( loggerName: 'main', serverName: 'server.dart', From 83c59d4ef5bb33c6c70fd3343537450439145faa Mon Sep 17 00:00:00 2001 From: rxlabz Date: Wed, 14 Oct 2020 14:12:42 +0200 Subject: [PATCH 12/13] rename every `environmentAttributes` to `environment` --- dart/lib/src/browser_client.dart | 14 +++++++------- dart/lib/src/client.dart | 10 +++++----- dart/lib/src/client_stub.dart | 2 +- dart/lib/src/io_client.dart | 14 +++++++------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/dart/lib/src/browser_client.dart b/dart/lib/src/browser_client.dart index 5ca60a0323..dd4607fa42 100644 --- a/dart/lib/src/browser_client.dart +++ b/dart/lib/src/browser_client.dart @@ -17,7 +17,7 @@ import 'version.dart'; SentryClient createSentryClient({ @required String dsn, - Event environmentAttributes, + Event environment, bool compressPayload, Client httpClient, dynamic clock, @@ -25,7 +25,7 @@ SentryClient createSentryClient({ }) => SentryBrowserClient( dsn: dsn, - environmentAttributes: environmentAttributes, + environment: environment, httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, @@ -36,7 +36,7 @@ class SentryBrowserClient extends SentryClient { /// Instantiates a client using [dsn] issued to your project by Sentry.io as /// the endpoint for submitting events. /// - /// [environmentAttributes] contain event attributes that do not change over + /// [environment] contain event attributes that do not change over /// the course of a program's lifecycle. These attributes will be added to /// all events captured via this client. The following attributes often fall /// under this category: [Event.serverName], [Event.release], [Event.environment]. @@ -55,7 +55,7 @@ class SentryBrowserClient extends SentryClient { /// tests. factory SentryBrowserClient({ @required String dsn, - Event environmentAttributes, + Event environment, Client httpClient, dynamic clock, UuidGenerator uuidGenerator, @@ -72,7 +72,7 @@ class SentryBrowserClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environmentAttributes: environmentAttributes, + environment: environment, dsn: dsn, origin: origin, platform: browserPlatform, @@ -83,7 +83,7 @@ class SentryBrowserClient extends SentryClient { Client httpClient, dynamic clock, UuidGenerator uuidGenerator, - Event environmentAttributes, + Event environment, String dsn, String platform, String origin, @@ -91,7 +91,7 @@ class SentryBrowserClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environmentAttributes: environmentAttributes, + environment: environment, dsn: dsn, platform: platform, origin: origin, diff --git a/dart/lib/src/client.dart b/dart/lib/src/client.dart index d7cfc8d728..0f1c5b3f64 100644 --- a/dart/lib/src/client.dart +++ b/dart/lib/src/client.dart @@ -31,7 +31,7 @@ abstract class SentryClient { }) => createSentryClient( dsn: dsn, - environmentAttributes: environment, + environment: environment, httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, @@ -43,7 +43,7 @@ abstract class SentryClient { dynamic clock, UuidGenerator uuidGenerator, String dsn, - this.environmentAttributes, + this.environment, String platform, this.origin, Sdk sdk, @@ -71,7 +71,7 @@ abstract class SentryClient { /// event to event, such as local operating system version, the version of /// Dart/Flutter SDK, etc. These attributes have lower precedence than those /// supplied in the even passed to [capture]. - final Event environmentAttributes; + final Event environment; final Dsn _dsn; @@ -155,8 +155,8 @@ abstract class SentryClient { 'timestamp': formatDateAsIso8601WithSecondPrecision(now), }; - if (environmentAttributes != null) { - mergeAttributes(environmentAttributes.toJson(), into: data); + if (environment != null) { + mergeAttributes(environment.toJson(), into: data); } // Merge the user context. diff --git a/dart/lib/src/client_stub.dart b/dart/lib/src/client_stub.dart index 882268db74..06bd7a4ff4 100644 --- a/dart/lib/src/client_stub.dart +++ b/dart/lib/src/client_stub.dart @@ -12,7 +12,7 @@ import 'utils.dart'; /// Implemented in `browser_client.dart` and `io_client.dart`. SentryClient createSentryClient({ @required String dsn, - Event environmentAttributes, + Event environment, bool compressPayload, Client httpClient, dynamic clock, diff --git a/dart/lib/src/io_client.dart b/dart/lib/src/io_client.dart index f45ecc57d2..4b2b4ba8bf 100644 --- a/dart/lib/src/io_client.dart +++ b/dart/lib/src/io_client.dart @@ -16,7 +16,7 @@ import 'version.dart'; SentryClient createSentryClient({ @required String dsn, - Event environmentAttributes, + Event environment, bool compressPayload, Client httpClient, dynamic clock, @@ -24,7 +24,7 @@ SentryClient createSentryClient({ }) => SentryIOClient( dsn: dsn, - environmentAttributes: environmentAttributes, + environment: environment, compressPayload: compressPayload, httpClient: httpClient, clock: clock, @@ -36,7 +36,7 @@ class SentryIOClient extends SentryClient { /// Instantiates a client using [dsn] issued to your project by Sentry.io as /// the endpoint for submitting events. /// - /// [environmentAttributes] contain event attributes that do not change over + /// [environment] contain event attributes that do not change over /// the course of a program's lifecycle. These attributes will be added to /// all events captured via this client. The following attributes often fall /// under this category: [Event.serverName], [Event.release], [Event.environment]. @@ -59,7 +59,7 @@ class SentryIOClient extends SentryClient { /// tests. factory SentryIOClient({ @required String dsn, - Event environmentAttributes, + Event environment, bool compressPayload, Client httpClient, dynamic clock, @@ -74,7 +74,7 @@ class SentryIOClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environmentAttributes: environmentAttributes, + environment: environment, dsn: dsn, compressPayload: compressPayload, platform: sdkPlatform, @@ -85,7 +85,7 @@ class SentryIOClient extends SentryClient { Client httpClient, dynamic clock, UuidGenerator uuidGenerator, - Event environmentAttributes, + Event environment, String dsn, this.compressPayload = true, String platform, @@ -94,7 +94,7 @@ class SentryIOClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environmentAttributes: environmentAttributes, + environment: environment, dsn: dsn, platform: platform, origin: origin, From f63ac278c1de1251a466920e0bd7d5c082477e34 Mon Sep 17 00:00:00 2001 From: rxlabz Date: Wed, 14 Oct 2020 16:25:27 +0200 Subject: [PATCH 13/13] revert `environmentAttributes` renaming --- dart/lib/src/browser_client.dart | 14 +++++++------- dart/lib/src/client.dart | 12 ++++++------ dart/lib/src/client_stub.dart | 2 +- dart/lib/src/io_client.dart | 14 +++++++------- dart/lib/src/sentry.dart | 2 +- dart/lib/src/sentry_options.dart | 4 ++-- dart/test/test_utils.dart | 8 ++++---- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/dart/lib/src/browser_client.dart b/dart/lib/src/browser_client.dart index dd4607fa42..5ca60a0323 100644 --- a/dart/lib/src/browser_client.dart +++ b/dart/lib/src/browser_client.dart @@ -17,7 +17,7 @@ import 'version.dart'; SentryClient createSentryClient({ @required String dsn, - Event environment, + Event environmentAttributes, bool compressPayload, Client httpClient, dynamic clock, @@ -25,7 +25,7 @@ SentryClient createSentryClient({ }) => SentryBrowserClient( dsn: dsn, - environment: environment, + environmentAttributes: environmentAttributes, httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, @@ -36,7 +36,7 @@ class SentryBrowserClient extends SentryClient { /// Instantiates a client using [dsn] issued to your project by Sentry.io as /// the endpoint for submitting events. /// - /// [environment] contain event attributes that do not change over + /// [environmentAttributes] contain event attributes that do not change over /// the course of a program's lifecycle. These attributes will be added to /// all events captured via this client. The following attributes often fall /// under this category: [Event.serverName], [Event.release], [Event.environment]. @@ -55,7 +55,7 @@ class SentryBrowserClient extends SentryClient { /// tests. factory SentryBrowserClient({ @required String dsn, - Event environment, + Event environmentAttributes, Client httpClient, dynamic clock, UuidGenerator uuidGenerator, @@ -72,7 +72,7 @@ class SentryBrowserClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environment: environment, + environmentAttributes: environmentAttributes, dsn: dsn, origin: origin, platform: browserPlatform, @@ -83,7 +83,7 @@ class SentryBrowserClient extends SentryClient { Client httpClient, dynamic clock, UuidGenerator uuidGenerator, - Event environment, + Event environmentAttributes, String dsn, String platform, String origin, @@ -91,7 +91,7 @@ class SentryBrowserClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environment: environment, + environmentAttributes: environmentAttributes, dsn: dsn, platform: platform, origin: origin, diff --git a/dart/lib/src/client.dart b/dart/lib/src/client.dart index 0f1c5b3f64..08cc0f8bc8 100644 --- a/dart/lib/src/client.dart +++ b/dart/lib/src/client.dart @@ -23,7 +23,7 @@ abstract class SentryClient { /// `dart:html` is available, otherwise it will throw an unsupported error. factory SentryClient({ @required String dsn, - Event environment, + Event environmentAttributes, bool compressPayload, Client httpClient, dynamic clock, @@ -31,7 +31,7 @@ abstract class SentryClient { }) => createSentryClient( dsn: dsn, - environment: environment, + environmentAttributes: environmentAttributes, httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, @@ -43,7 +43,7 @@ abstract class SentryClient { dynamic clock, UuidGenerator uuidGenerator, String dsn, - this.environment, + this.environmentAttributes, String platform, this.origin, Sdk sdk, @@ -71,7 +71,7 @@ abstract class SentryClient { /// event to event, such as local operating system version, the version of /// Dart/Flutter SDK, etc. These attributes have lower precedence than those /// supplied in the even passed to [capture]. - final Event environment; + final Event environmentAttributes; final Dsn _dsn; @@ -155,8 +155,8 @@ abstract class SentryClient { 'timestamp': formatDateAsIso8601WithSecondPrecision(now), }; - if (environment != null) { - mergeAttributes(environment.toJson(), into: data); + if (environmentAttributes != null) { + mergeAttributes(environmentAttributes.toJson(), into: data); } // Merge the user context. diff --git a/dart/lib/src/client_stub.dart b/dart/lib/src/client_stub.dart index 06bd7a4ff4..882268db74 100644 --- a/dart/lib/src/client_stub.dart +++ b/dart/lib/src/client_stub.dart @@ -12,7 +12,7 @@ import 'utils.dart'; /// Implemented in `browser_client.dart` and `io_client.dart`. SentryClient createSentryClient({ @required String dsn, - Event environment, + Event environmentAttributes, bool compressPayload, Client httpClient, dynamic clock, diff --git a/dart/lib/src/io_client.dart b/dart/lib/src/io_client.dart index 4b2b4ba8bf..f45ecc57d2 100644 --- a/dart/lib/src/io_client.dart +++ b/dart/lib/src/io_client.dart @@ -16,7 +16,7 @@ import 'version.dart'; SentryClient createSentryClient({ @required String dsn, - Event environment, + Event environmentAttributes, bool compressPayload, Client httpClient, dynamic clock, @@ -24,7 +24,7 @@ SentryClient createSentryClient({ }) => SentryIOClient( dsn: dsn, - environment: environment, + environmentAttributes: environmentAttributes, compressPayload: compressPayload, httpClient: httpClient, clock: clock, @@ -36,7 +36,7 @@ class SentryIOClient extends SentryClient { /// Instantiates a client using [dsn] issued to your project by Sentry.io as /// the endpoint for submitting events. /// - /// [environment] contain event attributes that do not change over + /// [environmentAttributes] contain event attributes that do not change over /// the course of a program's lifecycle. These attributes will be added to /// all events captured via this client. The following attributes often fall /// under this category: [Event.serverName], [Event.release], [Event.environment]. @@ -59,7 +59,7 @@ class SentryIOClient extends SentryClient { /// tests. factory SentryIOClient({ @required String dsn, - Event environment, + Event environmentAttributes, bool compressPayload, Client httpClient, dynamic clock, @@ -74,7 +74,7 @@ class SentryIOClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environment: environment, + environmentAttributes: environmentAttributes, dsn: dsn, compressPayload: compressPayload, platform: sdkPlatform, @@ -85,7 +85,7 @@ class SentryIOClient extends SentryClient { Client httpClient, dynamic clock, UuidGenerator uuidGenerator, - Event environment, + Event environmentAttributes, String dsn, this.compressPayload = true, String platform, @@ -94,7 +94,7 @@ class SentryIOClient extends SentryClient { httpClient: httpClient, clock: clock, uuidGenerator: uuidGenerator, - environment: environment, + environmentAttributes: environmentAttributes, dsn: dsn, platform: platform, origin: origin, diff --git a/dart/lib/src/sentry.dart b/dart/lib/src/sentry.dart index c695778e9b..382026acd5 100644 --- a/dart/lib/src/sentry.dart +++ b/dart/lib/src/sentry.dart @@ -21,7 +21,7 @@ class Sentry { optionsConfiguration(options); _client = SentryClient( dsn: options.dsn, - environment: options.environment, + environmentAttributes: options.environmentAttributes, compressPayload: options.compressPayload, httpClient: options.httpClient, clock: options.clock, diff --git a/dart/lib/src/sentry_options.dart b/dart/lib/src/sentry_options.dart index f379a3f1ef..76e5760ecb 100644 --- a/dart/lib/src/sentry_options.dart +++ b/dart/lib/src/sentry_options.dart @@ -19,7 +19,7 @@ class SentryOptions { /// event to event, such as local operating system version, the version of /// Dart/Flutter SDK, etc. These attributes have lower precedence than those /// supplied in the even passed to [capture]. - Event environment; + Event environmentAttributes; /// If [compressPayload] is `true` the outgoing HTTP payloads are compressed /// using gzip. Otherwise, the payloads are sent in plain UTF8-encoded JSON @@ -44,7 +44,7 @@ class SentryOptions { SentryOptions({ this.dsn, - this.environment, + this.environmentAttributes, this.compressPayload, this.httpClient, this.clock, diff --git a/dart/test/test_utils.dart b/dart/test/test_utils.dart index 431655226f..ecc0c676db 100644 --- a/dart/test/test_utils.dart +++ b/dart/test/test_utils.dart @@ -75,7 +75,7 @@ Future testCaptureException( clock: fakeClockProvider, uuidGenerator: () => 'X' * 32, compressPayload: compressPayload, - environment: const Event( + environmentAttributes: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging', @@ -235,7 +235,7 @@ void runTest({Codec, List> gzip, bool isWeb = false}) { clock: fakeClockProvider, compressPayload: false, uuidGenerator: () => 'X' * 32, - environment: const Event( + environmentAttributes: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging', @@ -293,7 +293,7 @@ void runTest({Codec, List> gzip, bool isWeb = false}) { clock: fakeClockProvider, uuidGenerator: () => 'X' * 32, compressPayload: false, - environment: const Event( + environmentAttributes: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging', @@ -350,7 +350,7 @@ void runTest({Codec, List> gzip, bool isWeb = false}) { clock: fakeClockProvider, uuidGenerator: () => 'X' * 32, compressPayload: false, - environment: const Event( + environmentAttributes: const Event( serverName: 'test.server.com', release: '1.2.3', environment: 'staging',