Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
36a151e
sync setuser to android
May 9, 2022
026a30f
set user on swift plugin
May 9, 2022
c0ea8f6
set extras
May 9, 2022
dfbefc4
add breadcrumb on andorid
May 10, 2022
83e28b5
add breadcrumb on cocoa
May 10, 2022
48ff46b
call add breadcrumb on scope
May 10, 2022
06d9393
clear breadcrumbs and set extra
May 10, 2022
7c8ff6c
support set tag
May 10, 2022
5001487
make method private
May 16, 2022
976810d
add remove extra and remove tag methods
May 16, 2022
6e2485e
remove extra & tag in plugins
May 16, 2022
5fee5ec
add set/remove setContexts
May 16, 2022
9f3ae5e
set/remove contexts
May 16, 2022
08849d9
Use statically exposed methods
May 16, 2022
2ad6e8b
call statically exposed methods on cocoa
May 16, 2022
80efc40
call toString instead of string cast
May 16, 2022
a84ed5a
remove redundant return types
May 16, 2022
c70c62e
Change return type to future
May 17, 2022
8eaee05
fix tests
May 17, 2022
667b818
add tests for native channel
May 17, 2022
073d25f
add senty native tests
May 17, 2022
959c888
test scope
May 17, 2022
082d195
revert last upgrade check
May 17, 2022
f59a05e
fix conflict
marandaneto May 20, 2022
9c685d4
prefer single imports
May 23, 2022
186f60e
provide old getter with deprecation annotation
May 23, 2022
e4e5721
Merge branch 'feat/sync-scope-to-native' of github.com:getsentry/sent…
May 23, 2022
300b177
Change FutureOr<void> to Future<void> return types.
May 23, 2022
418aa05
import single files
May 23, 2022
9c74a7d
remove unn semicolons
May 23, 2022
8ae857c
remove todos referencing scope sync
May 23, 2022
3b8cd9a
remove breadcrumbs if handled
May 23, 2022
ebf5633
revert xcode u version
May 23, 2022
fac7026
add missing import
May 23, 2022
708c13c
fix compile error in example
May 24, 2022
c0175dc
Add changelog entry
May 24, 2022
c29a4b4
run format
May 24, 2022
acde3fd
Merge branch 'main' into feat/sync-scope-to-native
May 30, 2022
b670762
Merge branch 'main' into feat/sync-scope-to-native
denrase Jun 7, 2022
557ae60
reduce nested depth
denrase Jun 7, 2022
757db8d
return attachments
denrase Jun 7, 2022
d29aa0b
await removeObservers
denrase Jun 7, 2022
69b05f9
await in clear
denrase Jun 7, 2022
73f1117
Merge branch 'main' into feat/sync-scope-to-native
denrase Jun 7, 2022
ab12d62
recreate baseline
denrase Jun 7, 2022
f12b240
add comment ho to recreate baseline
denrase Jun 7, 2022
fea9fd3
addd -cb param to recreate baseline in comment
denrase Jun 7, 2022
9cb6891
only run detekt in folders containing android code
denrase Jun 7, 2022
6198557
await clear in tests
denrase Jun 7, 2022
631eaaf
align case
denrase Jun 7, 2022
bee4089
disable swiftlint rules
denrase Jun 7, 2022
4236b3e
use shorthand syntactic sugar
denrase Jun 7, 2022
de28717
Merge branch 'main' into feat/sync-scope-to-native
marandaneto Jun 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/flutter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ jobs:
steps:
- uses: actions/checkout@v3
# 1.20.0
# To recreate baseline run: detekt -i flutter/android,flutter/example/android -b flutter/config/detekt-bl.xml -cb
- uses: natiginfo/action-detekt-all@74990bda6bfc47977e1e06aae9f47f320e7587ce
with:
args: -i flutter --baseline flutter/config/detekt-bl.xml
args: -i flutter/android,flutter/example/android --baseline flutter/config/detekt-bl.xml
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* Fix: Fix `SentryAssetBundle` on Flutter >= 3.1 (#877)
* Feat: Add Android thread to platform stacktraces (#853)
* Fix: Rename auto initialize property (#857)
* Feat: Sync Scope to Native (#858)
* Bump: Sentry-Android to 6.0.0-beta.4 (#871)
* Bump: Sentry-Android to 6.0.0 (#879)

## 6.6.0-alpha.2
Expand Down
14 changes: 7 additions & 7 deletions dart/example/bin/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ Future<void> runApp() async {
);

Sentry.configureScope((scope) {
scope.setUser(SentryUser(
id: '800',
username: 'first-user',
email: '[email protected]',
// ipAddress: '127.0.0.1', sendDefaultPii feature is enabled
extras: <String, String>{'first-sign-in': '2020-01-01'},
));
scope
..user = SentryUser(
id: '800',
username: 'first-user',
email: '[email protected]',
// ipAddress: '127.0.0.1', sendDefaultPii feature is enabled
extras: <String, String>{'first-sign-in': '2020-01-01'},
)
// ..fingerprint = ['example-dart'], fingerprint forces events to group together
..transaction = '/example/app'
..level = SentryLevel.warning
Expand Down
17 changes: 10 additions & 7 deletions dart/example_web/web/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,21 @@ void runApp() {

Sentry.configureScope((scope) {
scope
..user = SentryUser(
id: '800',
username: 'first-user',
email: '[email protected]',
// ipAddress: '127.0.0.1',
extras: <String, String>{'first-sign-in': '2020-01-01'},
)
// ..fingerprint = ['example-dart']
..transaction = '/example/app'
..level = SentryLevel.warning
..setTag('build', '579')
..setExtra('company-name', 'Dart Inc');

scope.setUser(
SentryUser(
id: '800',
username: 'first-user',
email: '[email protected]',
// ipAddress: '127.0.0.1',
extras: <String, String>{'first-sign-in': '2020-01-01'},
),
);
});

querySelector('#btEvent')
Expand Down
1 change: 1 addition & 0 deletions dart/lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export 'src/noop_isolate_error_integration.dart'
if (dart.library.io) 'src/isolate_error_integration.dart';
export 'src/protocol.dart';
export 'src/scope.dart';
export 'src/scope_observer.dart';
export 'src/sentry.dart';
export 'src/sentry_envelope.dart';
export 'src/sentry_envelope_item.dart';
Expand Down
88 changes: 67 additions & 21 deletions dart/lib/src/scope.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import 'dart:async';
import 'dart:collection';

import 'sentry_attachment/sentry_attachment.dart';
import 'event_processor.dart';
import 'protocol.dart';
import 'scope_observer.dart';
import 'sentry_attachment/sentry_attachment.dart';
import 'sentry_options.dart';
import 'sentry_span_interface.dart';
import 'sentry_tracer.dart';
import 'tracing.dart';

/// Scope data to be sent with the event
class Scope {
Expand Down Expand Up @@ -46,8 +48,17 @@ class Scope {
}
}

/// Information about the current user.
SentryUser? user;
SentryUser? _user;

/// Get the current user.
SentryUser? get user => _user;

/// Set the current user.
Future<void> setUser(SentryUser? user) async {
_user = user;
await _callScopeObservers(
(scopeObserver) async => await scopeObserver.setUser(user));
}

List<String> _fingerprint = [];

Expand Down Expand Up @@ -93,15 +104,21 @@ class Scope {
Map<String, dynamic> get contexts => Map.unmodifiable(_contexts);

/// add an entry to the Scope's contexts
void setContexts(String key, dynamic value) {
Future<void> setContexts(String key, dynamic value) async {
_contexts[key] = (value is num || value is bool || value is String)
? {'value': value}
: value;

await _callScopeObservers(
(scopeObserver) async => await scopeObserver.setContexts(key, value));
}

/// Removes a value from the Scope's contexts
void removeContexts(String key) {
Future<void> removeContexts(String key) async {
_contexts.remove(key);

await _callScopeObservers(
(scopeObserver) async => await scopeObserver.removeContexts(key));
}

/// Scope's event processor list
Expand All @@ -114,14 +131,17 @@ class Scope {

final SentryOptions _options;

final List<SentryAttachment> _attachements = [];
final List<SentryAttachment> _attachments = [];

List<SentryAttachment> get attachments => List.unmodifiable(_attachments);

List<SentryAttachment> get attachements => List.unmodifiable(_attachements);
@Deprecated('Use attachments instead')
List<SentryAttachment> get attachements => attachments;

Scope(this._options);

/// Adds a breadcrumb to the breadcrumbs queue
void addBreadcrumb(Breadcrumb breadcrumb, {dynamic hint}) {
Future<void> addBreadcrumb(Breadcrumb breadcrumb, {dynamic hint}) async {
// bail out if maxBreadcrumbs is zero
if (_options.maxBreadcrumbs == 0) {
return;
Expand Down Expand Up @@ -151,19 +171,25 @@ class Scope {
}

_breadcrumbs.add(breadcrumb);

await _callScopeObservers(
(scopeObserver) async => await scopeObserver.addBreadcrumb(breadcrumb));
}

void addAttachment(SentryAttachment attachment) {
_attachements.add(attachment);
_attachments.add(attachment);
}

void clearAttachments() {
_attachements.clear();
_attachments.clear();
}

/// Clear all the breadcrumbs
void clearBreadcrumbs() {
Future<void> clearBreadcrumbs() async {
_breadcrumbs.clear();

await _callScopeObservers(
(scopeObserver) async => await scopeObserver.clearBreadcrumbs());
}

/// Adds an event processor
Expand All @@ -172,36 +198,46 @@ class Scope {
}

/// Resets the Scope to its default state
void clear() {
clearBreadcrumbs();
Future<void> clear() async {
await clearBreadcrumbs();
clearAttachments();
level = null;
_span = null;
_transaction = null;
user = null;
await setUser(null);
_fingerprint = [];
_tags.clear();
_extra.clear();
_eventProcessors.clear();
}

/// Sets a tag to the Scope
void setTag(String key, String value) {
Future<void> setTag(String key, String value) async {
_tags[key] = value;
await _callScopeObservers(
(scopeObserver) async => await scopeObserver.setTag(key, value));
}

/// Removes a tag from the Scope
void removeTag(String key) {
Future<void> removeTag(String key) async {
_tags.remove(key);
await _callScopeObservers(
(scopeObserver) async => await scopeObserver.removeTag(key));
}

/// Sets an extra to the Scope
void setExtra(String key, dynamic value) {
Future<void> setExtra(String key, dynamic value) async {
_extra[key] = value;
await _callScopeObservers(
(scopeObserver) async => await scopeObserver.setExtra(key, value));
}

/// Removes an extra from the Scope
void removeExtra(String key) => _extra.remove(key);
Future<void> removeExtra(String key) async {
_extra.remove(key);
await _callScopeObservers(
(scopeObserver) async => await scopeObserver.removeExtra(key));
}

Future<SentryEvent?> applyToEvent(
SentryEvent event, {
Expand Down Expand Up @@ -327,11 +363,12 @@ class Scope {
Scope clone() {
final clone = Scope(_options)
..level = level
..user = user
..fingerprint = List.from(fingerprint)
.._transaction = _transaction
.._span = _span;

clone.setUser(user);

for (final tag in _tags.keys) {
clone.setTag(tag, _tags[tag]!);
}
Expand All @@ -354,10 +391,19 @@ class Scope {
}
});

for (final attachment in _attachements) {
for (final attachment in _attachments) {
clone.addAttachment(attachment);
}

return clone;
}

Future<void> _callScopeObservers(
Future<void> Function(ScopeObserver) action) async {
if (_options.enableScopeSync) {
for (final scopeObserver in _options.scopeObservers) {
await action(scopeObserver);
}
}
}
}
16 changes: 16 additions & 0 deletions dart/lib/src/scope_observer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'dart:async';

import 'protocol/breadcrumb.dart';
import 'protocol/sentry_user.dart';

abstract class ScopeObserver {
Future<void> setContexts(String key, dynamic value);
Future<void> removeContexts(String key);
Future<void> setUser(SentryUser? user);
Future<void> addBreadcrumb(Breadcrumb breadcrumb);
Future<void> clearBreadcrumbs();
Future<void> setExtra(String key, dynamic value);
Future<void> removeExtra(String key);
Future<void> setTag(String key, String value);
Future<void> removeTag(String key);
}
31 changes: 29 additions & 2 deletions dart/lib/src/sentry_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,24 @@ class SentryClient {
return _sentryId;
}
}

if (_options.platformChecker.platform.isAndroid &&
_options.enableScopeSync) {
/*
We do this to avoid duplicate breadcrumbs on Android as sentry-android applies the breadcrumbs
from the native scope onto every envelope sent through it. This scope will contain the breadcrumbs
sent through the scope sync feature. This causes duplicate breadcrumbs.
We then remove the breadcrumbs in all cases but if it is handled == false,
this is a signal that the app would crash and android would lose the breadcrumbs by the time the app is restarted to read
the envelope.
*/
preparedEvent = _eventWithRemovedBreadcrumbsIfHandled(preparedEvent);
}

final envelope = SentryEnvelope.fromEvent(
preparedEvent,
_options.sdk,
attachments: scope?.attachements,
attachments: scope?.attachments,
);

final id = await captureEnvelope(envelope);
Expand Down Expand Up @@ -297,7 +311,7 @@ class SentryClient {

final id = await captureEnvelope(
SentryEnvelope.fromTransaction(preparedTransaction, _options.sdk,
attachments: scope?.attachements
attachments: scope?.attachments
.where((element) => element.addToTransactions)
.toList()),
);
Expand Down Expand Up @@ -363,6 +377,19 @@ class SentryClient {
_options.recorder.recordLostEvent(reason, category);
}

SentryEvent _eventWithRemovedBreadcrumbsIfHandled(SentryEvent event) {
final exceptions = event.exceptions ?? [];
final handled = exceptions.isNotEmpty
? exceptions.first.mechanism?.handled == true
: false;

if (handled) {
return event.copyWith(breadcrumbs: []);
} else {
return event;
}
}

Future<SentryId?> _attachClientReportsAndSend(SentryEnvelope envelope) {
final clientReport = _options.recorder.flush();
envelope.addClientReport(clientReport);
Expand Down
12 changes: 11 additions & 1 deletion dart/lib/src/sentry_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import 'transport/noop_transport.dart';
import 'utils.dart';
import 'version.dart';

// TODO: Scope observers, enableScopeSync
// TODO: shutdownTimeout, flushTimeoutMillis
// https://api.dart.dev/stable/2.10.2/dart-io/HttpClient/close.html doesn't have a timeout param, we'd need to implement manually

Expand Down Expand Up @@ -269,6 +268,17 @@ class SentryOptions {
/// Send statistics to sentry when the client drops events.
bool sendClientReports = true;

/// If enabled, [scopeObservers] will be called when mutating scope.
bool enableScopeSync = true;

final List<ScopeObserver> _scopeObservers = [];

List<ScopeObserver> get scopeObservers => _scopeObservers;

void addScopeObserver(ScopeObserver scopeObserver) {
_scopeObservers.add(scopeObserver);
}

@internal
late ClientReportRecorder recorder = NoOpClientReportRecorder();

Expand Down
Loading