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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* Feat: Allow to set startTimestamp & endTimestamp manually to SentrySpan (#676)
* Bump: Sentry-Cocoa to 7.10.0 (#777)
* Feat: Additional Dart/Flutter context information (#778)
* Bump: Kotlin plugin to 1.5.31 (#763)
Expand Down
4 changes: 4 additions & 0 deletions dart/lib/src/hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ class Hub {
String name,
String operation, {
String? description,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand All @@ -354,6 +355,7 @@ class Hub {
operation,
description: description,
),
startTimestamp: startTimestamp,
bindToScope: bindToScope,
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
Expand All @@ -365,6 +367,7 @@ class Hub {
ISentrySpan startTransactionWithContext(
SentryTransactionContext transactionContext, {
Map<String, dynamic>? customSamplingContext,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand Down Expand Up @@ -395,6 +398,7 @@ class Hub {
final tracer = SentryTracer(
transactionContext,
this,
startTimestamp: startTimestamp,
waitForChildren: waitForChildren ?? false,
autoFinishAfter: autoFinishAfter,
trimEnd: trimEnd ?? false,
Expand Down
4 changes: 4 additions & 0 deletions dart/lib/src/hub_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class HubAdapter implements Hub {
ISentrySpan startTransactionWithContext(
SentryTransactionContext transactionContext, {
Map<String, dynamic>? customSamplingContext,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand All @@ -116,6 +117,7 @@ class HubAdapter implements Hub {
Sentry.startTransactionWithContext(
transactionContext,
customSamplingContext: customSamplingContext,
startTimestamp: startTimestamp,
bindToScope: bindToScope,
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
Expand All @@ -127,6 +129,7 @@ class HubAdapter implements Hub {
String name,
String operation, {
String? description,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand All @@ -137,6 +140,7 @@ class HubAdapter implements Hub {
name,
operation,
description: description,
startTimestamp: startTimestamp,
bindToScope: bindToScope,
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
Expand Down
2 changes: 2 additions & 0 deletions dart/lib/src/noop_hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class NoOpHub implements Hub {
String name,
String operation, {
String? description,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand All @@ -99,6 +100,7 @@ class NoOpHub implements Hub {
ISentrySpan startTransactionWithContext(
SentryTransactionContext transactionContext, {
Map<String, dynamic>? customSamplingContext,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand Down
8 changes: 6 additions & 2 deletions dart/lib/src/noop_sentry_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class NoOpSentrySpan extends ISentrySpan {
}

@override
Future<void> finish({SpanStatus? status}) async {}
Future<void> finish({SpanStatus? status, DateTime? endTimestamp}) async {}

@override
void removeData(String key) {}
Expand All @@ -41,7 +41,11 @@ class NoOpSentrySpan extends ISentrySpan {
void setTag(String key, String value) {}

@override
ISentrySpan startChild(String operation, {String? description}) =>
ISentrySpan startChild(
String operation, {
String? description,
DateTime? startTimestamp,
}) =>
NoOpSentrySpan();

@override
Expand Down
46 changes: 35 additions & 11 deletions dart/lib/src/protocol/sentry_span.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import '../utils.dart';

class SentrySpan extends ISentrySpan {
final SentrySpanContext _context;
DateTime? _timestamp;
final DateTime _startTimestamp = getUtcDateTime();
DateTime? _endTimestamp;
late final DateTime _startTimestamp;
final Hub _hub;

final SentryTracer _tracer;
Expand All @@ -19,7 +19,7 @@ class SentrySpan extends ISentrySpan {

SpanStatus? _status;
final Map<String, String> _tags = {};
void Function()? _finishedCallback;
void Function({DateTime? endTimestamp})? _finishedCallback;

@override
bool? sampled;
Expand All @@ -28,9 +28,11 @@ class SentrySpan extends ISentrySpan {
this._tracer,
this._context,
this._hub, {
DateTime? startTimestamp,
bool? sampled,
Function()? finishedCallback,
Function({DateTime? endTimestamp})? finishedCallback,
}) {
_startTimestamp = startTimestamp?.toUtc() ?? getUtcDateTime();
this.sampled = sampled;
_finishedCallback = finishedCallback;
}
Expand All @@ -41,17 +43,28 @@ class SentrySpan extends ISentrySpan {
return;
}

final utcDateTime = getUtcDateTime();

if (status != null) {
_status = status;
}
_timestamp = endTimestamp ?? getUtcDateTime();

if (endTimestamp?.isBefore(_startTimestamp) ?? false) {
_hub.options.logger(
SentryLevel.warning,
'End timestamp ($endTimestamp) cannot be before start timestamp ($_startTimestamp)',
);
_endTimestamp = utcDateTime;
} else {
_endTimestamp = endTimestamp?.toUtc() ?? utcDateTime;
}

// associate error
if (_throwable != null) {
_hub.setSpanContext(_throwable, this, _tracer.name);
}
_finishedCallback?.call();
await super.finish(status: status);
_finishedCallback?.call(endTimestamp: _endTimestamp);
await super.finish(status: status, endTimestamp: _endTimestamp);
}

@override
Expand Down Expand Up @@ -94,15 +107,25 @@ class SentrySpan extends ISentrySpan {
ISentrySpan startChild(
String operation, {
String? description,
DateTime? startTimestamp,
}) {
if (finished) {
return NoOpSentrySpan();
}

if (startTimestamp?.isBefore(_startTimestamp) ?? false) {
_hub.options.logger(
SentryLevel.warning,
"Start timestamp ($startTimestamp) cannot be before parent span's start timestamp ($_startTimestamp). Returning NoOpSpan.",
);
return NoOpSentrySpan();
}

return _tracer.startChildWithParentSpanId(
_context.spanId,
operation,
description: description,
startTimestamp: startTimestamp,
);
}

Expand All @@ -116,7 +139,7 @@ class SentrySpan extends ISentrySpan {
DateTime get startTimestamp => _startTimestamp;

@override
DateTime? get endTimestamp => _timestamp;
DateTime? get endTimestamp => _endTimestamp;

@override
SentrySpanContext get context => _context;
Expand All @@ -125,8 +148,9 @@ class SentrySpan extends ISentrySpan {
final json = _context.toJson();
json['start_timestamp'] =
formatDateAsIso8601WithMillisPrecision(_startTimestamp);
if (_timestamp != null) {
json['timestamp'] = formatDateAsIso8601WithMillisPrecision(_timestamp!);
if (_endTimestamp != null) {
json['timestamp'] =
formatDateAsIso8601WithMillisPrecision(_endTimestamp!);
}
if (_data.isNotEmpty) {
json['data'] = _data;
Expand All @@ -141,7 +165,7 @@ class SentrySpan extends ISentrySpan {
}

@override
bool get finished => _timestamp != null;
bool get finished => _endTimestamp != null;

@override
dynamic get throwable => _throwable;
Expand Down
4 changes: 4 additions & 0 deletions dart/lib/src/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ class Sentry {
String name,
String operation, {
String? description,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand All @@ -234,6 +235,7 @@ class Sentry {
name,
operation,
description: description,
startTimestamp: startTimestamp,
bindToScope: bindToScope,
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
Expand All @@ -245,6 +247,7 @@ class Sentry {
static ISentrySpan startTransactionWithContext(
SentryTransactionContext transactionContext, {
Map<String, dynamic>? customSamplingContext,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand All @@ -253,6 +256,7 @@ class Sentry {
_hub.startTransactionWithContext(
transactionContext,
customSamplingContext: customSamplingContext,
startTimestamp: startTimestamp,
bindToScope: bindToScope,
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
Expand Down
3 changes: 2 additions & 1 deletion dart/lib/src/sentry_span_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ abstract class ISentrySpan {
ISentrySpan startChild(
String operation, {
String? description,
DateTime? startTimestamp,
});

/// Sets the tag on span or transaction.
Expand All @@ -24,7 +25,7 @@ abstract class ISentrySpan {
void removeData(String key);

/// Sets span timestamp marking this span as finished.
Future<void> finish({SpanStatus? status}) async {}
Future<void> finish({SpanStatus? status, DateTime? endTimestamp}) async {}

/// Gets span status.
SpanStatus? get status;
Expand Down
41 changes: 29 additions & 12 deletions dart/lib/src/sentry_tracer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@ class SentryTracer extends ISentrySpan {
/// transaction after a given "idle time" and we don't want this "idle time"
/// to be part of the transaction.
SentryTracer(SentryTransactionContext transactionContext, this._hub,
{bool waitForChildren = false,
{DateTime? startTimestamp,
bool waitForChildren = false,
Duration? autoFinishAfter,
bool trimEnd = false}) {
_rootSpan = SentrySpan(
this,
transactionContext,
_hub,
sampled: transactionContext.sampled,
startTimestamp: startTimestamp,
);
_waitForChildren = waitForChildren;
if (autoFinishAfter != null) {
Expand All @@ -53,21 +55,27 @@ class SentryTracer extends ISentrySpan {
}

@override
Future<void> finish({SpanStatus? status}) async {
Future<void> finish({SpanStatus? status, DateTime? endTimestamp}) async {
final commonEndTimestamp = endTimestamp ?? getUtcDateTime();
_autoFinishAfterTimer?.cancel();
_finishStatus = SentryTracerFinishStatus.finishing(status);
if (!_rootSpan.finished &&
(!_waitForChildren || _haveAllChildrenFinished())) {
_rootSpan.status ??= status;

// finish unfinished spans otherwise transaction gets dropped
for (final span in _children) {
if (!span.finished) {
await span.finish(status: SpanStatus.deadlineExceeded());
}
}
// remove span where its endTimestamp is before startTimestamp
_children.removeWhere(
(span) => !_hasSpanSuitableTimestamps(span, commonEndTimestamp));

var _rootEndTimestamp = getUtcDateTime();
// finish unfinished spans otherwise transaction gets dropped
final spansToBeFinished = _children.where((span) => !span.finished);
await Future.forEach(
spansToBeFinished,
(SentrySpan span) async => await span.finish(
status: SpanStatus.deadlineExceeded(),
endTimestamp: commonEndTimestamp));

var _rootEndTimestamp = commonEndTimestamp;
if (_trimEnd && children.isNotEmpty) {
final childEndTimestamps = children
.where((child) => child.endTimestamp != null)
Expand Down Expand Up @@ -136,6 +144,7 @@ class SentryTracer extends ISentrySpan {
ISentrySpan startChild(
String operation, {
String? description,
DateTime? startTimestamp,
}) {
if (finished) {
return NoOpSentrySpan();
Expand All @@ -152,13 +161,15 @@ class SentryTracer extends ISentrySpan {
return _rootSpan.startChild(
operation,
description: description,
startTimestamp: startTimestamp,
);
}

ISentrySpan startChildWithParentSpanId(
SpanId parentSpanId,
String operation, {
String? description,
DateTime? startTimestamp,
}) {
if (finished) {
return NoOpSentrySpan();
Expand All @@ -178,11 +189,12 @@ class SentryTracer extends ISentrySpan {
operation: operation,
description: description);

final child = SentrySpan(this, context, _hub, sampled: _rootSpan.sampled,
finishedCallback: () {
final child = SentrySpan(this, context, _hub,
sampled: _rootSpan.sampled, startTimestamp: startTimestamp,
finishedCallback: ({DateTime? endTimestamp}) {
final finishStatus = _finishStatus;
if (finishStatus.finishing) {
finish(status: finishStatus.status);
finish(status: finishStatus.status, endTimestamp: endTimestamp);
}
});

Expand Down Expand Up @@ -235,4 +247,9 @@ class SentryTracer extends ISentrySpan {
}
return true;
}

bool _hasSpanSuitableTimestamps(
SentrySpan span, DateTime endTimestampCandidate) =>
!span.startTimestamp
.isAfter((span.endTimestamp ?? endTimestampCandidate));
}
1 change: 1 addition & 0 deletions dart/test/default_integrations_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ class PrintRecursionMockHub extends MockHub {
ISentrySpan startTransactionWithContext(
SentryTransactionContext transactionContext, {
Map<String, dynamic>? customSamplingContext,
DateTime? startTimestamp,
bool? bindToScope,
bool? waitForChildren,
Duration? autoFinishAfter,
Expand Down
Loading