Skip to content

Commit f49a663

Browse files
committed
Merge remote-tracking branch 'origin/main' into feature/frame-tracking
2 parents d435299 + 6206e85 commit f49a663

36 files changed

+822
-28
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Unreleased
22

3+
* Fix: captureTransaction should return emptyId when transaction is discarded (#713)
4+
5+
# 6.3.0-beta.3
6+
7+
* Feat: Auto transactions duration trimming (#702)
8+
* Add `SentryAssetBundle` for automatic spans for asset loading (#685)
39
* Feat: Configure idle transaction duration (#705)
410
* Fix: `maxRequestBodySize` should be `never` by default when using the FailedRequestClientAdapter directly (#701)
511

dart/lib/src/hub.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ class Hub {
342342
bool? bindToScope,
343343
bool? waitForChildren,
344344
Duration? autoFinishAfter,
345+
bool? trimEnd,
345346
Map<String, dynamic>? customSamplingContext,
346347
}) =>
347348
startTransactionWithContext(
@@ -353,6 +354,7 @@ class Hub {
353354
bindToScope: bindToScope,
354355
waitForChildren: waitForChildren,
355356
autoFinishAfter: autoFinishAfter,
357+
trimEnd: trimEnd,
356358
customSamplingContext: customSamplingContext,
357359
);
358360

@@ -363,6 +365,7 @@ class Hub {
363365
bool? bindToScope,
364366
bool? waitForChildren,
365367
Duration? autoFinishAfter,
368+
bool? trimEnd,
366369
}) {
367370
if (!_isEnabled) {
368371
_options.logger(
@@ -391,6 +394,7 @@ class Hub {
391394
this,
392395
waitForChildren: waitForChildren ?? false,
393396
autoFinishAfter: autoFinishAfter,
397+
trimEnd: trimEnd ?? false,
394398
);
395399
if (bindToScope ?? false) {
396400
item.scope.span = tracer;

dart/lib/src/hub_adapter.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,15 @@ class HubAdapter implements Hub {
104104
bool? bindToScope,
105105
bool? waitForChildren,
106106
Duration? autoFinishAfter,
107+
bool? trimEnd,
107108
}) =>
108109
Sentry.startTransactionWithContext(
109110
transactionContext,
110111
customSamplingContext: customSamplingContext,
111112
bindToScope: bindToScope,
112113
waitForChildren: waitForChildren,
113114
autoFinishAfter: autoFinishAfter,
115+
trimEnd: trimEnd,
114116
);
115117

116118
@override
@@ -121,6 +123,7 @@ class HubAdapter implements Hub {
121123
bool? bindToScope,
122124
bool? waitForChildren,
123125
Duration? autoFinishAfter,
126+
bool? trimEnd,
124127
Map<String, dynamic>? customSamplingContext,
125128
}) =>
126129
Sentry.startTransaction(
@@ -130,6 +133,7 @@ class HubAdapter implements Hub {
130133
bindToScope: bindToScope,
131134
waitForChildren: waitForChildren,
132135
autoFinishAfter: autoFinishAfter,
136+
trimEnd: trimEnd,
133137
customSamplingContext: customSamplingContext,
134138
);
135139

dart/lib/src/noop_hub.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class NoOpHub implements Hub {
8080
bool? bindToScope,
8181
bool? waitForChildren,
8282
Duration? autoFinishAfter,
83+
bool? trimEnd,
8384
Map<String, dynamic>? customSamplingContext,
8485
}) =>
8586
NoOpSentrySpan();
@@ -91,6 +92,7 @@ class NoOpHub implements Hub {
9192
bool? bindToScope,
9293
bool? waitForChildren,
9394
Duration? autoFinishAfter,
95+
bool? trimEnd,
9496
}) =>
9597
NoOpSentrySpan();
9698

dart/lib/src/protocol/sentry_span.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ class SentrySpan extends ISentrySpan {
3636
}
3737

3838
@override
39-
Future<void> finish({SpanStatus? status}) async {
39+
Future<void> finish({SpanStatus? status, DateTime? endTimestamp}) async {
4040
if (finished) {
4141
return;
4242
}
4343

4444
if (status != null) {
4545
_status = status;
4646
}
47-
_timestamp = getUtcDateTime();
47+
_timestamp = endTimestamp ?? getUtcDateTime();
4848

4949
// associate error
5050
if (_throwable != null) {

dart/lib/src/sentry.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ class Sentry {
231231
bool? bindToScope,
232232
bool? waitForChildren,
233233
Duration? autoFinishAfter,
234+
bool? trimEnd,
234235
Map<String, dynamic>? customSamplingContext,
235236
}) =>
236237
_hub.startTransaction(
@@ -240,6 +241,7 @@ class Sentry {
240241
bindToScope: bindToScope,
241242
waitForChildren: waitForChildren,
242243
autoFinishAfter: autoFinishAfter,
244+
trimEnd: trimEnd,
243245
customSamplingContext: customSamplingContext,
244246
);
245247

@@ -250,13 +252,15 @@ class Sentry {
250252
bool? bindToScope,
251253
bool? waitForChildren,
252254
Duration? autoFinishAfter,
255+
bool? trimEnd,
253256
}) =>
254257
_hub.startTransactionWithContext(
255258
transactionContext,
256259
customSamplingContext: customSamplingContext,
257260
bindToScope: bindToScope,
258261
waitForChildren: waitForChildren,
259262
autoFinishAfter: autoFinishAfter,
263+
trimEnd: trimEnd,
260264
);
261265

262266
/// Gets the current active transaction or span.

dart/lib/src/sentry_client.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ class SentryClient {
261261

262262
final id = await captureEnvelope(
263263
SentryEnvelope.fromTransaction(preparedTransaction, _options.sdk));
264-
return id!;
264+
return id ?? SentryId.empty();
265265
}
266266

267267
/// Reports the [envelope] to Sentry.io.

dart/lib/src/sentry_tracer.dart

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22

33
import 'package:meta/meta.dart';
4+
import 'utils.dart';
45

56
import '../sentry.dart';
67
import 'sentry_tracer_finish_status.dart';
@@ -16,9 +17,25 @@ class SentryTracer extends ISentrySpan {
1617
final Map<String, dynamic> _extra = {};
1718
Timer? _autoFinishAfterTimer;
1819
var _finishStatus = SentryTracerFinishStatus.notFinishing();
19-
20+
late final bool _trimEnd;
21+
22+
/// If [waitForChildren] is true, this transaction will not finish until all
23+
/// its children are finished.
24+
///
25+
/// When [autoFinishAfter] is provided, started transactions will
26+
/// automatically be finished after this duration.
27+
///
28+
/// If [trimEnd] is true, sets the end timestamp of the transaction to the
29+
/// highest timestamp of child spans, trimming the duration of the
30+
/// transaction. This is useful to discard extra time in the transaction that
31+
/// is not accounted for in child spans, like what happens in the
32+
/// [SentryNavigatorObserver] idle transactions, where we finish the
33+
/// transaction after a given "idle time" and we don't want this "idle time"
34+
/// to be part of the transaction.
2035
SentryTracer(SentryTransactionContext transactionContext, this._hub,
21-
{bool waitForChildren = false, Duration? autoFinishAfter}) {
36+
{bool waitForChildren = false,
37+
Duration? autoFinishAfter,
38+
bool trimEnd = false}) {
2239
_rootSpan = SentrySpan(
2340
this,
2441
transactionContext,
@@ -32,6 +49,7 @@ class SentryTracer extends ISentrySpan {
3249
});
3350
}
3451
name = transactionContext.name;
52+
_trimEnd = trimEnd;
3553
}
3654

3755
@override
@@ -41,7 +59,6 @@ class SentryTracer extends ISentrySpan {
4159
if (!_rootSpan.finished &&
4260
(!_waitForChildren || _haveAllChildrenFinished())) {
4361
_rootSpan.status ??= status;
44-
await _rootSpan.finish();
4562

4663
// finish unfinished spans otherwise transaction gets dropped
4764
for (final span in _children) {
@@ -50,6 +67,23 @@ class SentryTracer extends ISentrySpan {
5067
}
5168
}
5269

70+
var _rootEndTimestamp = getUtcDateTime();
71+
if (_trimEnd && children.isNotEmpty) {
72+
final childEndTimestamps = children
73+
.where((child) => child.endTimestamp != null)
74+
.map((child) => child.endTimestamp!);
75+
76+
if (childEndTimestamps.isNotEmpty) {
77+
final oldestChildEndTimestamp =
78+
childEndTimestamps.reduce((a, b) => a.isAfter(b) ? a : b);
79+
if (_rootEndTimestamp.isAfter(oldestChildEndTimestamp)) {
80+
_rootEndTimestamp = oldestChildEndTimestamp;
81+
}
82+
}
83+
}
84+
85+
await _rootSpan.finish(endTimestamp: _rootEndTimestamp);
86+
5387
// remove from scope
5488
_hub.configureScope((scope) {
5589
if (scope.span == this) {

dart/lib/src/version.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
library version;
1010

1111
/// The SDK version reported to Sentry.io in the submitted events.
12-
const String sdkVersion = '6.3.0-beta.3';
12+
const String sdkVersion = '6.3.0-beta.4';
1313

1414
String sdkName(bool isWeb) => isWeb ? _browserSdkName : _ioSdkName;
1515

dart/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: sentry
2-
version: 6.3.0-beta.3
2+
version: 6.3.0-beta.4
33
description: >
44
A crash reporting library for Dart that sends crash reports to Sentry.io.
55
This library supports Dart VM and Web. For Flutter consider sentry_flutter instead.

dart/test/default_integrations_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ class PrintRecursionMockHub extends MockHub {
190190
bool? bindToScope,
191191
bool? waitForChildren,
192192
Duration? autoFinishAfter,
193+
bool? trimEnd,
193194
}) {
194195
return NoOpSentrySpan();
195196
}

dart/test/mocks/mock_hub.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class MockHub implements Hub {
127127
bool? bindToScope,
128128
bool? waitForChildren,
129129
Duration? autoFinishAfter,
130+
bool? trimEnd,
130131
Map<String, dynamic>? customSamplingContext,
131132
}) {
132133
return NoOpSentrySpan();
@@ -139,6 +140,7 @@ class MockHub implements Hub {
139140
bool? bindToScope,
140141
bool? waitForChildren,
141142
Duration? autoFinishAfter,
143+
bool? trimEnd,
142144
}) {
143145
return NoOpSentrySpan();
144146
}

dart/test/sentry_client_test.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,14 @@ void main() {
346346

347347
expect(capturedEvent['exception'], isNull);
348348
});
349+
350+
test('should return empty for when transaction is discarded', () async {
351+
final client = fixture.getSut(eventProcessor: DropAllEventProcessor());
352+
final tr = SentryTransaction(fixture.tracer);
353+
final id = await client.captureTransaction(tr);
354+
355+
expect(id, SentryId.empty());
356+
});
349357
});
350358

351359
group('SentryClient : apply scope to the captured event', () {

dart/test/sentry_span_test.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,16 @@ void main() {
181181

182182
expect(numberOfCallbackCalls, 1);
183183
});
184+
185+
test('optional endTimestamp set instead of current time', () async {
186+
final sut = fixture.getSut();
187+
188+
final endTimestamp = DateTime.now().add(Duration(days: 1));
189+
190+
await sut.finish(endTimestamp: endTimestamp);
191+
192+
expect(sut.endTimestamp, endTimestamp);
193+
});
184194
}
185195

186196
class Fixture {

dart/test/sentry_tracer_test.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,53 @@ void main() {
236236
await sut.finish();
237237
expect(sut.finished, true);
238238
});
239+
240+
test('end trimmed to last child', () async {
241+
final sut = fixture.getSut(
242+
trimEnd: true, autoFinishAfter: Duration(milliseconds: 200));
243+
244+
final childA = sut.startChild('operation-a', description: 'description');
245+
final childB = sut.startChild('operation-b', description: 'description');
246+
247+
await childA.finish();
248+
await Future.delayed(Duration(milliseconds: 10));
249+
await childB.finish();
250+
await Future.delayed(Duration(milliseconds: 210));
251+
252+
expect(sut.endTimestamp, childB.endTimestamp);
253+
});
254+
255+
test('end trimmed to child', () async {
256+
final sut = fixture.getSut(
257+
trimEnd: true, autoFinishAfter: Duration(milliseconds: 200));
258+
259+
final childA = sut.startChild('operation-a', description: 'description');
260+
261+
await childA.finish();
262+
await Future.delayed(Duration(milliseconds: 210));
263+
264+
expect(sut.endTimestamp, childA.endTimestamp);
265+
});
266+
267+
test('end not trimmed when no child', () async {
268+
final sut = fixture.getSut(
269+
trimEnd: true, autoFinishAfter: Duration(milliseconds: 200));
270+
271+
await Future.delayed(Duration(milliseconds: 210));
272+
273+
expect(sut.endTimestamp, isNotNull);
274+
});
275+
276+
test('end not trimmed when no finished child', () async {
277+
final sut = fixture.getSut(
278+
trimEnd: true, autoFinishAfter: Duration(milliseconds: 200));
279+
280+
sut.startChild('operation-a', description: 'description');
281+
282+
await Future.delayed(Duration(milliseconds: 210));
283+
284+
expect(sut.endTimestamp, isNotNull);
285+
});
239286
}
240287

241288
class Fixture {
@@ -244,6 +291,7 @@ class Fixture {
244291
SentryTracer getSut({
245292
bool? sampled = true,
246293
bool waitForChildren = false,
294+
bool trimEnd = false,
247295
Duration? autoFinishAfter,
248296
}) {
249297
final context = SentryTransactionContext(
@@ -256,6 +304,7 @@ class Fixture {
256304
hub,
257305
waitForChildren: waitForChildren,
258306
autoFinishAfter: autoFinishAfter,
307+
trimEnd: trimEnd,
259308
);
260309
}
261310
}

dio/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: sentry_dio
22
description: An integration which adds support for performance tracing for the Dio package.
3-
version: 6.3.0-beta.3
3+
version: 6.3.0-beta.4
44
homepage: https://docs.sentry.io/platforms/dart/
55
repository: https://github.com/getsentry/sentry-dart
66
issue_tracker: https://github.com/getsentry/sentry-dart/issues

dio/test/mocks/mock_hub.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class MockHub implements Hub {
133133
bool? bindToScope,
134134
bool? waitForChildren,
135135
Duration? autoFinishAfter,
136+
bool? trimEnd,
136137
Map<String, dynamic>? customSamplingContext,
137138
}) {
138139
return NoOpSentrySpan();
@@ -145,6 +146,7 @@ class MockHub implements Hub {
145146
bool? bindToScope,
146147
bool? waitForChildren,
147148
Duration? autoFinishAfter,
149+
bool? trimEnd,
148150
}) {
149151
return NoOpSentrySpan();
150152
}

0 commit comments

Comments
 (0)