@@ -7,19 +7,23 @@ import '../../sentry_flutter.dart';
7
7
import '../integrations/integrations.dart' ;
8
8
import '../native/sentry_native.dart' ;
9
9
import 'display_strategy_evaluator.dart' ;
10
+ import 'time_to_display_transaction_handler.dart' ;
10
11
11
12
@internal
12
13
class TimeToDisplayTracker {
13
14
final Hub _hub;
14
- final bool _enableAutoTransactions;
15
- final Duration _autoFinishAfter;
16
15
final SentryNative ? _native;
16
+ final TimeToDisplayTransactionHandler _transactionHandler;
17
17
18
18
static DateTime ? _startTimestamp;
19
19
static DateTime ? _ttidEndTimestamp;
20
20
static ISentrySpan ? _ttidSpan;
21
21
static ISentrySpan ? _ttfdSpan;
22
22
static Timer ? _ttfdTimer;
23
+ static ISentrySpan ? _transaction;
24
+
25
+ @visibleForTesting
26
+ Duration ttfdAutoFinishAfter = Duration (seconds: 30 );
23
27
24
28
SentryFlutterOptions ? get _options => _hub.options is SentryFlutterOptions
25
29
// ignore: invalid_use_of_internal_member
@@ -30,75 +34,17 @@ class TimeToDisplayTracker {
30
34
required Hub ? hub,
31
35
required bool enableAutoTransactions,
32
36
required Duration autoFinishAfter,
37
+ TimeToDisplayTransactionHandler ? transactionHandler,
33
38
}) : _hub = hub ?? HubAdapter (),
34
- _enableAutoTransactions = enableAutoTransactions,
35
- _autoFinishAfter = autoFinishAfter,
36
- _native = SentryFlutter .native ;
37
-
38
- Future <ISentrySpan ?> _startTransaction (String ? routeName, Object ? arguments,
39
- {DateTime ? startTimestamp}) async {
40
- if (! _enableAutoTransactions) {
41
- return null ;
42
- }
43
-
44
- if (routeName == null ) {
45
- return null ;
46
- }
47
-
48
- if (routeName == '/' ) {
49
- routeName = 'root ("/")' ;
50
- }
51
-
52
- final transactionContext = SentryTransactionContext (
53
- routeName,
54
- 'ui.load' ,
55
- transactionNameSource: SentryTransactionNameSource .component,
56
- // ignore: invalid_use_of_internal_member
57
- origin: SentryTraceOrigins .autoNavigationRouteObserver,
58
- );
59
-
60
- final transaction = _hub.startTransactionWithContext (
61
- transactionContext,
62
- waitForChildren: true ,
63
- autoFinishAfter: _autoFinishAfter,
64
- trimEnd: true ,
65
- bindToScope: true ,
66
- startTimestamp: startTimestamp,
67
- onFinish: (transaction) async {
68
- final nativeFrames = await _native
69
- ? .endNativeFramesCollection (transaction.context.traceId);
70
- if (nativeFrames != null ) {
71
- final measurements = nativeFrames.toMeasurements ();
72
- for (final item in measurements.entries) {
73
- final measurement = item.value;
74
- transaction.setMeasurement (
75
- item.key,
76
- measurement.value,
77
- unit: measurement.unit,
39
+ _native = SentryFlutter .native ,
40
+ _transactionHandler = transactionHandler ??
41
+ TimeToDisplayTransactionHandler (
42
+ hub: hub,
43
+ enableAutoTransactions: enableAutoTransactions,
44
+ autoFinishAfter: autoFinishAfter,
78
45
);
79
- }
80
- }
81
- },
82
- );
83
-
84
- // if _enableAutoTransactions is enabled but there's no traces sample rate
85
- if (transaction is NoOpSentrySpan ) {
86
- return null ;
87
- }
88
-
89
- if (arguments != null ) {
90
- transaction.setData ('route_settings_arguments' , arguments);
91
- }
92
-
93
- await _native? .beginNativeFramesCollection ();
94
-
95
- return transaction;
96
- }
97
46
98
47
void startMeasurement (String ? routeName, Object ? arguments) async {
99
- _ttidSpan = null ;
100
- _ttfdSpan = null ;
101
-
102
48
final startTimestamp = DateTime .now ();
103
49
_startTimestamp = startTimestamp;
104
50
@@ -123,27 +69,37 @@ class TimeToDisplayTracker {
123
69
final routeName = SentryNavigatorObserver .currentRouteName;
124
70
if (appStartInfo == null || routeName == null ) return ;
125
71
126
- final transaction = await _startTransaction (routeName, arguments,
72
+ final transaction = await _transactionHandler.startTransaction (
73
+ routeName, arguments,
127
74
startTimestamp: appStartInfo.start);
128
75
if (transaction == null ) return ;
76
+ _transaction = transaction;
129
77
130
- final ttidSpan =
131
- _createTTIDSpan (transaction, routeName, appStartInfo.start);
78
+ final ttidSpan = _transactionHandler.createSpan (
79
+ transaction,
80
+ TimeToDisplayType .timeToInitialDisplay,
81
+ routeName,
82
+ appStartInfo.start);
132
83
if (_options? .enableTimeToFullDisplayTracing == true ) {
133
- _ttfdSpan = _createTTFDSpan (transaction, routeName, appStartInfo.start);
84
+ _ttfdSpan = _transactionHandler.createSpan (transaction,
85
+ TimeToDisplayType .timeToFullDisplay, routeName, appStartInfo.start);
134
86
}
135
- _finishSpan (ttidSpan, transaction, appStartInfo.end,
87
+ TimeToDisplayTransactionHandler .finishSpan (
88
+ transaction: transaction,
89
+ span: ttidSpan,
90
+ endTimestamp: appStartInfo.end,
136
91
measurement: appStartInfo.measurement);
137
92
});
138
93
}
139
94
140
95
// Handles measuring navigation for regular routes
141
96
void _handleRegularRouteMeasurement (
142
97
String ? routeName, Object ? arguments, DateTime startTimestamp) async {
143
- final transaction = await _startTransaction (routeName, arguments,
144
- startTimestamp: startTimestamp);
98
+ final transaction = await _transactionHandler
99
+ . startTransaction (routeName, arguments, startTimestamp: startTimestamp);
145
100
146
101
if (transaction == null || routeName == null ) return ;
102
+ _transaction = transaction;
147
103
148
104
_initializeTimeToDisplaySpans (transaction, routeName, startTimestamp);
149
105
@@ -155,36 +111,43 @@ class TimeToDisplayTracker {
155
111
156
112
void _initializeTimeToDisplaySpans (
157
113
ISentrySpan transaction, String routeName, DateTime startTimestamp) {
158
- _ttidSpan = _createTTIDSpan (transaction, routeName, startTimestamp);
114
+ _ttidSpan = _transactionHandler.createSpan (transaction,
115
+ TimeToDisplayType .timeToInitialDisplay, routeName, startTimestamp);
159
116
if (_options? .enableTimeToFullDisplayTracing == true ) {
160
- _ttfdSpan = _createTTFDSpan (transaction, routeName, startTimestamp);
161
- final ttfdAutoFinishAfter = Duration (seconds: 30 );
162
- _ttfdTimer = Timer (ttfdAutoFinishAfter, () {
163
- if (_ttfdSpan? .finished == true ) {
117
+ _ttfdSpan = _transactionHandler.createSpan (transaction,
118
+ TimeToDisplayType .timeToFullDisplay, routeName, startTimestamp);
119
+ _ttfdTimer = Timer (ttfdAutoFinishAfter, () async {
120
+ final ttfdSpan = _ttfdSpan;
121
+ final ttfdEndTimestamp = _ttidEndTimestamp;
122
+ if (ttfdSpan == null ||
123
+ ttfdSpan.finished == true ||
124
+ ttfdEndTimestamp == null ) {
164
125
return ;
165
126
}
166
- _finishSpan (_ttfdSpan! , transaction, _ttidEndTimestamp! ,
127
+ TimeToDisplayTransactionHandler .finishSpan (
128
+ transaction: transaction,
129
+ span: ttfdSpan,
130
+ endTimestamp: ttfdEndTimestamp,
167
131
status: SpanStatus .deadlineExceeded ());
168
132
});
169
133
}
170
134
}
171
135
172
- ISentrySpan _createTTIDSpan (
173
- ISentrySpan transaction, String routeName, DateTime startTimestamp) {
174
- return transaction.startChild (
175
- SentryTraceOrigins .uiTimeToInitialDisplay,
176
- description: '$routeName initial display' ,
177
- startTimestamp: startTimestamp,
178
- );
179
- }
136
+ void _finishInitialDisplay (ISentrySpan ttidSpan, ISentrySpan transaction,
137
+ String routeName, DateTime startTimestamp) async {
138
+ final endTimestamp = await _determineEndTimeOfTTID (routeName);
139
+ if (endTimestamp == null ) return ;
140
+ _ttidEndTimestamp = endTimestamp;
180
141
181
- ISentrySpan _createTTFDSpan (
182
- ISentrySpan transaction, String routeName, DateTime startTimestamp) {
183
- return transaction.startChild (
184
- SentryTraceOrigins .uiTimeToFullDisplay,
185
- description: '$routeName full display' ,
186
- startTimestamp: startTimestamp,
187
- );
142
+ final duration = endTimestamp.difference (startTimestamp).inMilliseconds;
143
+ final measurement = SentryMeasurement ('time_to_initial_display' , duration,
144
+ unit: DurationSentryMeasurementUnit .milliSecond);
145
+
146
+ TimeToDisplayTransactionHandler .finishSpan (
147
+ transaction: transaction,
148
+ span: ttidSpan,
149
+ endTimestamp: endTimestamp,
150
+ measurement: measurement);
188
151
}
189
152
190
153
Future <DateTime ?> _determineEndTimeOfTTID (String routeName) async {
@@ -216,43 +179,21 @@ class TimeToDisplayTracker {
216
179
217
180
@internal
218
181
static void reportFullyDisplayed () {
219
- _finishFullDisplay ();
220
- }
221
-
222
- static void _finishFullDisplay () {
223
182
_ttfdTimer? .cancel ();
224
183
final endTimestamp = DateTime .now ();
225
184
final startTimestamp = _startTimestamp;
226
- final transaction = Sentry . getSpan () ;
185
+ final transaction = _transaction ;
227
186
final ttfdSpan = _ttfdSpan;
228
187
if (startTimestamp == null || transaction == null || ttfdSpan == null ) {
229
188
return ;
230
189
}
231
190
final duration = endTimestamp.difference (startTimestamp).inMilliseconds;
232
191
final measurement = SentryMeasurement ('time_to_full_display' , duration,
233
192
unit: DurationSentryMeasurementUnit .milliSecond);
234
- _finishSpan (ttfdSpan, transaction, endTimestamp, measurement: measurement);
235
- }
236
-
237
- void _finishInitialDisplay (ISentrySpan ttidSpan, ISentrySpan transaction,
238
- String routeName, DateTime startTimestamp) async {
239
- final endTimestamp = await _determineEndTimeOfTTID (routeName);
240
- if (endTimestamp == null ) return ;
241
- _ttidEndTimestamp = endTimestamp;
242
-
243
- final duration = endTimestamp.difference (startTimestamp).inMilliseconds;
244
- final measurement = SentryMeasurement ('time_to_initial_display' , duration,
245
- unit: DurationSentryMeasurementUnit .milliSecond);
246
- _finishSpan (ttidSpan, transaction, endTimestamp, measurement: measurement);
247
- }
248
-
249
- static void _finishSpan (
250
- ISentrySpan span, ISentrySpan transaction, DateTime endTimestamp,
251
- {SentryMeasurement ? measurement, SpanStatus ? status}) {
252
- if (measurement != null ) {
253
- transaction.setMeasurement (measurement.name, measurement.value,
254
- unit: measurement.unit);
255
- }
256
- span.finish (status: status, endTimestamp: endTimestamp);
193
+ TimeToDisplayTransactionHandler .finishSpan (
194
+ transaction: transaction,
195
+ span: ttfdSpan,
196
+ endTimestamp: endTimestamp,
197
+ measurement: measurement);
257
198
}
258
199
}
0 commit comments