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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
- Added Scope and Breadcrumb ring buffer #109
- Added Hub to SDK #113
- Ref: Hub passes the Scope to SentryClient
- feat: sentry options #116
- Feat: sentry options #116
- Ref: SentryId generates UUID

# `package:sentry` changelog

Expand Down
5 changes: 0 additions & 5 deletions dart/lib/src/browser_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,9 @@ class SentryBrowserClient extends SentryClient {
/// 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).
///
/// 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.
factory SentryBrowserClient(SentryOptions options, {String origin}) {
options.httpClient ??= BrowserClient();
options.clock ??= getUtcDateTime;
options.uuidGenerator ??= generateUuidV4WithoutDashes;

// origin is necessary for sentry to resolve stacktrace
origin ??= '${window.location.origin}/';
Expand Down
4 changes: 2 additions & 2 deletions dart/lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ abstract class SentryClient {

final data = <String, dynamic>{
'project': projectId,
'event_id': options.uuidGenerator(),
'event_id': event.eventId.toString(),
'timestamp': formatDateAsIso8601WithSecondPrecision(now),
};

Expand Down Expand Up @@ -158,7 +158,7 @@ abstract class SentryClient {
}

final eventId = json.decode(response.body)['id'];
return eventId != null ? SentryId(eventId) : SentryId.empty();
return eventId != null ? SentryId.fromId(eventId) : SentryId.empty();
}

/// Reports the [throwable] and optionally its [stackTrace] to Sentry.io.
Expand Down
3 changes: 1 addition & 2 deletions dart/lib/src/hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@ class Hub {
try {
sentryId = await item.client.captureEvent(event, scope: item.scope);
} catch (err) {
/* TODO add Event.id */
_options.logger(
SentryLevel.error,
'Error while capturing event with id: ${event}',
'Error while capturing event with id: ${event.eventId.toString()}',
);
} finally {
_lastEventId = sentryId;
Expand Down
4 changes: 0 additions & 4 deletions dart/lib/src/io_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,6 @@ class SentryIOClient extends SentryClient {
/// 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).
///
/// 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.
factory SentryIOClient(SentryOptions options) => SentryIOClient._(options);

SentryIOClient._(SentryOptions options) : super.base(options);
Expand Down
14 changes: 12 additions & 2 deletions dart/lib/src/protocol/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import '../version.dart';
@immutable
class Event {
/// Creates an event.
const Event({
Event({
SentryId eventId,
this.loggerName,
this.serverName,
this.release,
Expand All @@ -26,14 +27,17 @@ class Event {
this.contexts,
this.breadcrumbs,
this.sdk,
});
}) : eventId = eventId ?? SentryId.newId();

/// Refers to the default fingerprinting algorithm.
///
/// You do not need to specify this value unless you supplement the default
/// fingerprint with custom fingerprints.
static const String defaultFingerprint = '{{ default }}';

/// The ID Sentry.io assigned to the submitted event for future reference.
final SentryId eventId;

/// The logger that logged the event.
final String loggerName;

Expand Down Expand Up @@ -117,6 +121,7 @@ class Event {
final Sdk sdk;

Event copyWith({
SentryId eventId,
String loggerName,
String serverName,
String release,
Expand All @@ -136,6 +141,7 @@ class Event {
Sdk sdk,
}) =>
Event(
eventId: eventId ?? this.eventId,
loggerName: loggerName ?? this.loggerName,
serverName: serverName ?? this.serverName,
release: release ?? this.release,
Expand All @@ -162,6 +168,10 @@ class Event {
'platform': sdkPlatform,
};

if (eventId != null) {
json['event_id'] = eventId.toString();
}

if (loggerName != null) {
json['logger'] = loggerName;
}
Expand Down
22 changes: 16 additions & 6 deletions dart/lib/src/protocol/sentry_id.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
/// Sentry response id
import 'package:uuid/uuid.dart';

class SentryId {
static const String _emptyId = '00000000-0000-0000-0000-000000000000';
static final SentryId _emptyId =
SentryId.fromId('00000000-0000-0000-0000-000000000000');

/// The ID Sentry.io assigned to the submitted event for future reference.
final String _id;
String _id;

// TODO: should we generate the new UUID here with an empty ctor?
final Uuid _uuidGenerator = Uuid();

const SentryId(this._id);
SentryId._internal({String id}) {
_id = id ?? _uuidGenerator.v4();
}

factory SentryId.empty() => SentryId(_emptyId);
/// Generates a new SentryId
factory SentryId.newId() => SentryId._internal();

/// Generates a SentryId with the given UUID
factory SentryId.fromId(String id) => SentryId._internal(id: id);

/// SentryId with an empty UUID
factory SentryId.empty() => _emptyId;

@override
String toString() => _id.replaceAll('-', '');
Expand Down
7 changes: 0 additions & 7 deletions dart/lib/src/sentry_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'package:sentry/sentry.dart';
import 'diagnostic_logger.dart';
import 'hub.dart';
import 'protocol.dart';
import 'utils.dart';

/// Sentry SDK options
class SentryOptions {
Expand Down Expand Up @@ -39,11 +38,6 @@ class SentryOptions {
/// from [`package:quiver`](https://pub.dartlang.org/packages/quiver).
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.
UuidGenerator uuidGenerator;

int maxBreadcrumbs;

/// Logger interface to log useful debugging information if debug is enabled
Expand Down Expand Up @@ -145,7 +139,6 @@ class SentryOptions {
this.compressPayload,
this.httpClient,
this.clock,
this.uuidGenerator,
});

/// Adds an event processor
Expand Down
5 changes: 0 additions & 5 deletions dart/lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,6 @@
// found in the LICENSE file.

import 'package:meta/meta.dart';
import 'package:uuid/uuid.dart';

typedef UuidGenerator = String Function();

String generateUuidV4WithoutDashes() => Uuid().v4().replaceAll('-', '');

/// Sentry does not take a timezone and instead expects the date-time to be
/// submitted in UTC timezone.
Expand Down
8 changes: 5 additions & 3 deletions dart/test/event_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ void main() {
);
});
test('$Sdk serializes', () {
const event = Event(
final event = Event(
eventId: SentryId.empty(),
sdk: Sdk(
name: 'sentry.dart.flutter',
version: '4.3.2',
integrations: <String>['integration'],
packages: <Package>[Package('npm:@sentry/javascript', '1.3.4')]));
expect(event.toJson(), <String, dynamic>{
'platform': 'dart',
'event_id': '00000000000000000000000000000000',
'sdk': {
'name': 'sentry.dart.flutter',
'version': '4.3.2',
Expand All @@ -58,10 +60,9 @@ void main() {

final error = StateError('test-error');

print('error.stackTrace ${error.stackTrace}');

expect(
Event(
eventId: SentryId.empty(),
message: Message(
'test-message 1 2',
template: 'test-message %d %d',
Expand All @@ -85,6 +86,7 @@ void main() {
).toJson(),
<String, dynamic>{
'platform': 'dart',
'event_id': '00000000000000000000000000000000',
'sdk': {'version': sdkVersion, 'name': 'sentry.dart'},
'message': {
'formatted': 'test-message 1 2',
Expand Down
39 changes: 22 additions & 17 deletions dart/test/test_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ Future testCaptureException(
fail('Unexpected request on ${request.method} ${request.url} in HttpMock');
});

var sentryId = SentryId.empty();
final client = SentryClient(
SentryOptions(
dsn: testDsn,
httpClient: httpMock,
clock: fakeClockProvider,
uuidGenerator: () => 'X' * 32,
compressPayload: compressPayload,
environmentAttributes: const Event(
environmentAttributes: Event(
serverName: 'test.server.com',
release: '1.2.3',
environment: 'staging',
Expand All @@ -87,8 +87,7 @@ Future testCaptureException(
try {
throw ArgumentError('Test error');
} catch (error, stackTrace) {
final sentryId =
await client.captureException(error, stackTrace: stackTrace);
sentryId = await client.captureException(error, stackTrace: stackTrace);
expect('$sentryId', 'testeventid');
}

Expand All @@ -108,6 +107,10 @@ Future testCaptureException(
} else {
data = json.decode(utf8.decode(body)) as Map<String, dynamic>;
}

// so we assert the generated and returned id
data['event_id'] = sentryId.toString();

final stacktrace = data.remove('stacktrace') as Map<String, dynamic>;

expect(stacktrace['frames'], const TypeMatcher<List>());
Expand Down Expand Up @@ -139,7 +142,7 @@ Future testCaptureException(

expect(data, {
'project': '1',
'event_id': 'X' * 32,
'event_id': sentryId.toString(),
'timestamp': '2017-01-02T00:00:00',
'platform': 'javascript',
'sdk': {'version': sdkVersion, 'name': 'sentry.dart'},
Expand All @@ -157,7 +160,7 @@ Future testCaptureException(

expect(data, {
'project': '1',
'event_id': 'X' * 32,
'event_id': sentryId.toString(),
'timestamp': '2017-01-02T00:00:00',
'platform': 'dart',
'exception': [
Expand Down Expand Up @@ -235,8 +238,7 @@ void runTest({Codec<List<int>, List<int>> gzip, bool isWeb = false}) {
httpClient: httpMock,
clock: fakeClockProvider,
compressPayload: false,
uuidGenerator: () => 'X' * 32,
environmentAttributes: const Event(
environmentAttributes: Event(
serverName: 'test.server.com',
release: '1.2.3',
environment: 'staging',
Expand Down Expand Up @@ -292,9 +294,8 @@ void runTest({Codec<List<int>, List<int>> gzip, bool isWeb = false}) {
dsn: testDsn,
httpClient: httpMock,
clock: fakeClockProvider,
uuidGenerator: () => 'X' * 32,
compressPayload: false,
environmentAttributes: const Event(
environmentAttributes: Event(
serverName: 'test.server.com',
release: '1.2.3',
environment: 'staging',
Expand Down Expand Up @@ -348,9 +349,8 @@ void runTest({Codec<List<int>, List<int>> gzip, bool isWeb = false}) {
dsn: testDsn,
httpClient: httpMock,
clock: fakeClockProvider,
uuidGenerator: () => 'X' * 32,
compressPayload: false,
environmentAttributes: const Event(
environmentAttributes: Event(
serverName: 'test.server.com',
release: '1.2.3',
environment: 'staging',
Expand All @@ -362,12 +362,17 @@ void runTest({Codec<List<int>, List<int>> gzip, bool isWeb = false}) {
try {
throw ArgumentError('Test error');
} catch (error, stackTrace) {
final eventWithoutContext =
Event(exception: error, stackTrace: stackTrace);
final eventWithoutContext = Event(
eventId: SentryId.empty(),
exception: error,
stackTrace: stackTrace,
);
final eventWithContext = Event(
exception: error,
stackTrace: stackTrace,
userContext: eventUserContext);
eventId: SentryId.empty(),
exception: error,
stackTrace: stackTrace,
userContext: eventUserContext,
);
await client.captureEvent(eventWithoutContext);
expect(loggedUserId, clientUserContext.id);
await client.captureEvent(eventWithContext);
Expand Down