Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
- 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
- expect a sdkName based on the test platform #105
- Added Scope and Breadcrumb ring buffer #109

# `package:sentry` changelog

Expand Down
73 changes: 73 additions & 0 deletions dart/example/event_example.dart
Original file line number Diff line number Diff line change
@@ -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 <String, String>{'project-id': '7371'},
extra: const <String, String>{'company-name': 'Dart Inc'},
fingerprint: const <String>['example-dart'],
userContext: const User(
id: '800',
username: 'first-user',
email: '[email protected]',
ipAddress: '127.0.0.1',
extras: <String, String>{'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',
),
),
);
101 changes: 16 additions & 85 deletions dart/example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import 'dart:io';

import 'package:sentry/sentry.dart';

import 'event_example.dart';

/// Sends a test exception report to Sentry.io using this Dart client.
Future<void> main(List<String> rawArgs) async {
if (rawArgs.length != 1) {
Expand All @@ -16,18 +18,26 @@ Future<void> main(List<String> rawArgs) async {
}

final dsn = rawArgs.single;
final client = SentryClient(dsn: dsn);
Sentry.init((options) => options.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,
);

Expand All @@ -37,89 +47,10 @@ Future<void> main(List<String> rawArgs) async {
print('FAILURE: ${response.error}');
}
} finally {
await client.close();
await Sentry.close();
}
}

Future<void> 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 <String, String>{'project-id': '7371'},
extra: const <String, String>{'company-name': 'Dart Inc'},
fingerprint: const <String>['example-dart'],
userContext: const User(
id: '800',
username: 'first-user',
email: '[email protected]',
ipAddress: '127.0.0.1',
extras: <String, String>{'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',
)));

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}');
}
/* TODO(rxlabz) Sentry CaptureMessage(message, level) */
}

Future<void> foo() async {
Expand Down
4 changes: 4 additions & 0 deletions dart/lib/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
/// A pure Dart client for Sentry.io crash reporting.
export 'src/client.dart';
export 'src/protocol.dart';
export 'src/sentry.dart';
export 'src/sentry_options.dart';
export 'src/version.dart';
export 'src/scope.dart';
export 'src/sentry_options.dart';
139 changes: 139 additions & 0 deletions dart/lib/src/scope.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
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;

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/<username>/"`.
String _transaction;

String get transaction => _transaction;

set transaction(String transaction) {
_transaction = transaction;
}

/// Information about the current 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.
///
/// Example:
///
/// // A completely custom fingerprint:
/// var custom = ['foo', 'bar', 'baz'];
List<String> _fingerprint;

List<String> get fingerprint =>
_fingerprint != null ? List.unmodifiable(_fingerprint) : null;

set fingerprint(List<String> fingerprint) {
_fingerprint = 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 = {};

Map<String, String> 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<String, dynamic> _extra = {};

Map<String, dynamic> get extra => Map.unmodifiable(_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();
}

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