@@ -45,12 +45,6 @@ class NavigationTimingManager {
45
45
}
46
46
47
47
void startMeasurement (String routeName) async {
48
- final options = _hub.options is SentryFlutterOptions
49
- // ignore: invalid_use_of_internal_member
50
- ? _hub.options as SentryFlutterOptions
51
- : null ;
52
-
53
- // This marks the start timestamp of both TTID and TTFD spans
54
48
_startTimestamp = DateTime .now ();
55
49
56
50
// This has multiple branches
@@ -62,107 +56,106 @@ class NavigationTimingManager {
62
56
// App start - this is a special edge case that only happens once
63
57
AppStartTracker ().onAppStartComplete ((appStartInfo) {
64
58
// Create a transaction based on app start start time
65
- // Create ttidSpan and finish immediately with the app start start & end time
66
- // This is a small workaround to pass the correct time stamps since we mutate
59
+ // Then create ttidSpan and finish immediately with the app start start & end time
60
+ // This is a small workaround to pass the correct time stamps since we cannot mutate
67
61
// timestamps of transactions or spans in history
68
62
if (appStartInfo != null ) {
69
63
final transaction = _transactionManager? .startTransaction (
70
64
routeName, appStartInfo.start);
71
65
if (transaction != null ) {
72
- final ttidSpan = _startTimeToInitialDisplaySpan (
73
- routeName, transaction, appStartInfo.start);
66
+ final ttidSpan = _createTTIDSpan (transaction, routeName, appStartInfo.start);
74
67
ttidSpan.finish (endTimestamp: appStartInfo.end);
75
68
}
76
69
}
77
70
});
78
71
} else {
79
- DateTime ? approximationEndTime;
80
- final endTimeCompleter = Completer <DateTime >();
81
72
final transaction =
82
73
_transactionManager? .startTransaction (routeName, _startTimestamp! );
83
74
84
- if (transaction != null ) {
85
- if (options? .enableTimeToFullDisplayTracing == true ) {
86
- _ttfdSpan = transaction.startChild ('ui.load.full_display' ,
87
- description: '$routeName full display' ,
88
- startTimestamp: _startTimestamp! );
89
-
90
- _ttfdSpan = _startTimeToFullDisplaySpan (
91
- routeName, transaction, _startTimestamp! );
92
- }
93
- _ttidSpan = _startTimeToInitialDisplaySpan (
94
- routeName, transaction, _startTimestamp! );
75
+ if (transaction == null ) {
76
+ return ;
95
77
}
96
78
97
- SchedulerBinding .instance.addPostFrameCallback ((timeStamp) {
98
- approximationEndTime = DateTime .now ();
99
- endTimeCompleter.complete (approximationEndTime);
100
- });
79
+ _initializeSpans (transaction, routeName, _startTimestamp! );
101
80
102
- final strategyDecision =
103
- await SentryDisplayTracker ().decideStrategyWithTimeout2 (routeName);
104
-
105
- switch (strategyDecision) {
106
- case StrategyDecision .manual:
107
- final endTimestamp = DateTime .now ();
108
- final duration = endTimestamp.millisecondsSinceEpoch -
109
- _startTimestamp! .millisecondsSinceEpoch;
110
- _endTimeToInitialDisplaySpan (_ttidSpan! , transaction! , endTimestamp, duration);
111
- break ;
112
- case StrategyDecision .approximation:
113
- if (approximationEndTime == null ) {
114
- await endTimeCompleter.future;
115
- }
116
- final duration = approximationEndTime! .millisecondsSinceEpoch -
117
- _startTimestamp! .millisecondsSinceEpoch;
118
- _endTimeToInitialDisplaySpan (
119
- _ttidSpan! , transaction! , approximationEndTime! , duration);
120
- await _ttidSpan? .finish (endTimestamp: approximationEndTime);
121
- break ;
122
- default :
123
- print ('Unknown strategy decision: $strategyDecision ' );
124
- }
81
+ final endTimestamp = await _determineEndTime (routeName);
82
+
83
+ final duration = endTimestamp.difference (_startTimestamp! ).inMilliseconds;
84
+ _finishSpan (_ttidSpan! , transaction, 'time_to_initial_display' , duration,
85
+ endTimestamp);
125
86
}
126
87
}
127
88
89
+ Future <DateTime > _determineEndTime (String routeName) async {
90
+ DateTime ? approximationEndTime;
91
+ final endTimeCompleter = Completer <DateTime >();
92
+
93
+ SchedulerBinding .instance.addPostFrameCallback ((_) {
94
+ approximationEndTime = DateTime .now ();
95
+ endTimeCompleter.complete (approximationEndTime! );
96
+ });
97
+
98
+ final strategyDecision =
99
+ await SentryDisplayTracker ().decideStrategyWithTimeout2 (routeName);
100
+
101
+ if (strategyDecision == StrategyDecision .manual &&
102
+ ! endTimeCompleter.isCompleted) {
103
+ approximationEndTime = DateTime .now ();
104
+ endTimeCompleter.complete (approximationEndTime);
105
+ } else if (! endTimeCompleter.isCompleted) {
106
+ // If the decision is not manual and the completer hasn't been completed, await it.
107
+ await endTimeCompleter.future;
108
+ }
109
+
110
+ return approximationEndTime! ;
111
+ }
112
+
128
113
void reportInitiallyDisplayed (String routeName) {
129
114
SentryDisplayTracker ().reportManual2 (routeName);
130
115
}
131
116
132
117
void reportFullyDisplayed () {
133
- final endTime = DateTime .now ();
118
+ final endTimestamp = DateTime .now ();
134
119
final transaction = Sentry .getSpan ();
135
- final duration = endTime.millisecondsSinceEpoch -
136
- _startTimestamp! .millisecondsSinceEpoch;
137
- if (_ttfdSpan != null && transaction != null ) {
138
- _endTimeToFullDisplaySpan (_ttfdSpan! , transaction, endTime, duration);
120
+ final duration = endTimestamp.difference (_startTimestamp! ).inMilliseconds;
121
+ if (_ttidSpan == null || transaction == null ) {
122
+ return ;
139
123
}
124
+ _finishSpan (_ttfdSpan! , transaction, 'time_to_full_display' , duration, endTimestamp);
140
125
}
141
126
142
- static ISentrySpan _startTimeToInitialDisplaySpan (
143
- String routeName, ISentrySpan transaction, DateTime startTimestamp) {
144
- return transaction.startChild (SentryTraceOrigins .uiTimeToInitialDisplay,
145
- description: '$routeName initial display' ,
146
- startTimestamp: startTimestamp);
127
+ void _initializeSpans (ISentrySpan ? transaction, String routeName, DateTime startTimestamp) {
128
+ final options = _hub.options is SentryFlutterOptions
129
+ // ignore: invalid_use_of_internal_member
130
+ ? _hub.options as SentryFlutterOptions
131
+ : null ;
132
+ if (transaction == null ) return ;
133
+ _ttidSpan = _createTTIDSpan (transaction, routeName, startTimestamp);
134
+ if (options? .enableTimeToFullDisplayTracing == true ) {
135
+ _ttfdSpan = _createTTFDSpan (transaction, routeName, startTimestamp);
136
+ }
147
137
}
148
138
149
- static ISentrySpan _startTimeToFullDisplaySpan (
150
- String routeName, ISentrySpan transaction, DateTime startTimestamp) {
151
- return transaction.startChild (SentryTraceOrigins .uiTimeToFullDisplay,
152
- description: '$routeName full display' , startTimestamp: startTimestamp);
139
+ ISentrySpan _createTTIDSpan (ISentrySpan transaction, String routeName, DateTime startTimestamp) {
140
+ return transaction.startChild (
141
+ SentryTraceOrigins .uiTimeToInitialDisplay,
142
+ description: '$routeName initial display' ,
143
+ startTimestamp: startTimestamp,
144
+ );
153
145
}
154
146
155
- static void _endTimeToInitialDisplaySpan (ISentrySpan ttidSpan,
156
- ISentrySpan transaction, DateTime endTimestamp, int duration) async {
157
- transaction.setMeasurement ('time_to_initial_display' , duration,
158
- unit: DurationSentryMeasurementUnit .milliSecond);
159
- await ttidSpan.finish (endTimestamp: endTimestamp);
147
+ ISentrySpan _createTTFDSpan (ISentrySpan transaction, String routeName, DateTime startTimestamp) {
148
+ return transaction.startChild (
149
+ SentryTraceOrigins .uiTimeToFullDisplay,
150
+ description: '$routeName full display' ,
151
+ startTimestamp: startTimestamp,
152
+ );
160
153
}
161
154
162
- static void _endTimeToFullDisplaySpan (ISentrySpan ttfdSpan ,
163
- ISentrySpan transaction, DateTime endTimestamp, int duration) async {
164
- transaction.setMeasurement ('time_to_full_display' , duration,
155
+ void _finishSpan (ISentrySpan span, ISentrySpan transaction ,
156
+ String measurementName, int duration, DateTime endTimestamp) {
157
+ transaction.setMeasurement (measurementName , duration,
165
158
unit: DurationSentryMeasurementUnit .milliSecond);
166
- await ttfdSpan .finish (endTimestamp: endTimestamp);
159
+ span .finish (endTimestamp: endTimestamp);
167
160
}
168
161
}
0 commit comments