1
+ import 'package:flutter/scheduler.dart' ;
1
2
import 'package:flutter/widgets.dart' ;
2
3
import 'package:meta/meta.dart' ;
3
4
@@ -86,13 +87,18 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
86
87
final RouteNameExtractor ? _routeNameExtractor;
87
88
final AdditionalInfoExtractor ? _additionalInfoProvider;
88
89
final SentryNative ? _native;
90
+ static ISentrySpan ? _transaction2;
91
+
92
+ static ISentrySpan ? get transaction2 => _transaction2;
89
93
90
94
ISentrySpan ? _transaction;
91
95
92
96
static String ? _currentRouteName;
93
97
94
98
@internal
95
99
static String ? get currentRouteName => _currentRouteName;
100
+ static var startTime = DateTime .now ();
101
+ static ISentrySpan ? ttidSpan;
96
102
97
103
@override
98
104
void didPush (Route <dynamic > route, Route <dynamic >? previousRoute) {
@@ -108,7 +114,36 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
108
114
);
109
115
110
116
_finishTransaction ();
117
+
118
+ var routeName = route.settings.name ?? 'Unknown' ;
119
+
111
120
_startTransaction (route);
121
+
122
+ // Start timing
123
+ DateTime ? approximationEndTimestamp;
124
+ int ? approximationDurationMillis;
125
+
126
+ SchedulerBinding .instance.addPostFrameCallback ((timeStamp) {
127
+ approximationEndTimestamp = DateTime .now ();
128
+ approximationDurationMillis =
129
+ approximationEndTimestamp! .millisecond - startTime.millisecond;
130
+ });
131
+
132
+ SentryDisplayTracker ().startTimeout (routeName, () {
133
+ _transaction2? .setMeasurement (
134
+ 'time_to_initial_display' , approximationDurationMillis! ,
135
+ unit: DurationSentryMeasurementUnit .milliSecond);
136
+ ttidSpan? .setTag ('measurement' , 'approximation' );
137
+ ttidSpan? .finish (endTimestamp: approximationEndTimestamp! );
138
+ });
139
+ }
140
+
141
+ void freezeUIForSeconds (int seconds) {
142
+ var sw = Stopwatch ()..start ();
143
+ while (sw.elapsed.inSeconds < seconds) {
144
+ // This loop will block the UI thread.
145
+ }
146
+ sw.stop ();
112
147
}
113
148
114
149
@override
@@ -193,16 +228,26 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
193
228
if (name == '/' ) {
194
229
name = 'root ("/")' ;
195
230
}
196
- final transactionContext = SentryTransactionContext (
231
+ // final transactionContext = SentryTransactionContext(
232
+ // name,
233
+ // 'navigation',
234
+ // transactionNameSource: SentryTransactionNameSource.component,
235
+ // // ignore: invalid_use_of_internal_member
236
+ // origin: SentryTraceOrigins.autoNavigationRouteObserver,
237
+ // );
238
+
239
+ final transactionContext2 = SentryTransactionContext (
197
240
name,
198
- 'navigation ' ,
241
+ 'ui.load ' ,
199
242
transactionNameSource: SentryTransactionNameSource .component,
200
243
// ignore: invalid_use_of_internal_member
201
244
origin: SentryTraceOrigins .autoNavigationRouteObserver,
202
245
);
203
246
204
- _transaction = _hub.startTransactionWithContext (
205
- transactionContext,
247
+ // IMPORTANT -> we need to wait for ttid/ttfd children to finish AND wait [autoFinishAfter] afterwards so the user can add additional spans
248
+ // right now it auto finishes when ttid/ttfd finishes but that doesn't allow the user to add spans within the idle timeout
249
+ _transaction2 = _hub.startTransactionWithContext (
250
+ transactionContext2,
206
251
waitForChildren: true ,
207
252
autoFinishAfter: _autoFinishAfter,
208
253
trimEnd: true ,
@@ -225,24 +270,33 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
225
270
226
271
// if _enableAutoTransactions is enabled but there's no traces sample rate
227
272
if (_transaction is NoOpSentrySpan ) {
228
- _transaction = null ;
273
+ _transaction2 = null ;
229
274
return ;
230
275
}
231
276
277
+ startTime = DateTime .now ();
278
+ ttidSpan = _transaction2? .startChild ('ui.load.initial_display' );
279
+ ttidSpan? .origin = 'auto.ui.time_to_display' ;
280
+ ttidSpan? .setData ('test' , 'cachea' );
281
+
282
+ // Needs to finish after 30 seconds
283
+ // If not then it will finish with status deadline exceeded
284
+ // final ttfdSpan = _transaction2?.startChild('ui.load.full_display');
285
+
232
286
if (arguments != null ) {
233
- _transaction ? .setData ('route_settings_arguments' , arguments);
287
+ _transaction2 ? .setData ('route_settings_arguments' , arguments);
234
288
}
235
289
236
290
await _hub.configureScope ((scope) {
237
- scope.span ?? = _transaction ;
291
+ scope.span ?? = _transaction2 ;
238
292
});
239
293
240
294
await _native? .beginNativeFramesCollection ();
241
295
}
242
296
243
- Future <void > _finishTransaction () async {
244
- _transaction ? .status ?? = SpanStatus .ok ();
245
- await _transaction ? .finish ();
297
+ Future <void > _finishTransaction ({ DateTime ? endTimestamp} ) async {
298
+ _transaction2 ? .status ?? = SpanStatus .ok ();
299
+ await _transaction2 ? .finish (endTimestamp : endTimestamp );
246
300
}
247
301
}
248
302
0 commit comments