Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
2 changes: 2 additions & 0 deletions dart/lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
84 changes: 84 additions & 0 deletions dart/lib/src/scope.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
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/<username>/"`.
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<String> fingerprint;

/// List of breadcrumbs for this scope.
///
/// See also:
/// * https://docs.sentry.io/enriching-error-data/breadcrumbs/?platform=javascript
final Queue<Breadcrumb> _breadcrumbs = Queue();

/// Unmodifiable List of breadcrumbs
List<Breadcrumb> get breadcrumbs => List.unmodifiable(_breadcrumbs);

/// Name/value pairs that events can be searched by.
final Map<String, String> 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<String, dynamic> extra = {};

// TODO: eventProcessors, Contexts, BeforeBreadcrumbCallback, Breadcrumb hint, clone

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");

// 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();
}

_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();
}
}
5 changes: 5 additions & 0 deletions dart/lib/src/sentry_options.dart
Original file line number Diff line number Diff line change
@@ -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;
}
2 changes: 1 addition & 1 deletion dart/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dependencies:
uuid: ^2.0.0

dev_dependencies:
mockito: ^4.1.2
mockito: ^4.1.1
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because of null-safety, this is not working right thru the IDE, downgrading version made it to work

pedantic: ^1.9.2
test: ^1.15.4
yaml: ^2.2.1
Expand Down
238 changes: 238 additions & 0 deletions dart/test/scope_test.dart
Original file line number Diff line number Diff line change
@@ -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);
}
}