Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ttfd #1920

Merged
merged 120 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from 119 commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
0b21267
Change app start integration in a way that works with ttid as well
buenaflor Mar 1, 2024
6f6e71c
Formatting
buenaflor Mar 1, 2024
6ed7700
Update
buenaflor Mar 1, 2024
2f8a47d
add visibleForTesting
buenaflor Mar 1, 2024
50f298b
Update
buenaflor Mar 1, 2024
3477e6f
update
buenaflor Mar 4, 2024
dc80015
Merge branch 'main' into feat/ttid-appstart
buenaflor Mar 4, 2024
ed3d4ae
Add app start info test
buenaflor Mar 4, 2024
81346de
Remove set app start info null
buenaflor Mar 4, 2024
9d09211
Merge branch 'main' into feat/ttid-appstart
buenaflor Mar 4, 2024
cf5af40
Review improvements
buenaflor Mar 4, 2024
c653eb1
Merge branch 'main' into feat/ttid-appstart
buenaflor Mar 4, 2024
487e55f
Add TTID
buenaflor Mar 4, 2024
845e6a8
Improvements
buenaflor Mar 4, 2024
96c8766
Improvements
buenaflor Mar 4, 2024
1d9e71f
Fix integration test
buenaflor Mar 4, 2024
e3c227f
Merge branch 'main' into feat/ttid
buenaflor Mar 4, 2024
cea12c5
Update
buenaflor Mar 4, 2024
9af3455
Clear after tracking
buenaflor Mar 4, 2024
71fd7ec
Update CHANGELOG
buenaflor Mar 4, 2024
7a977fb
Format
buenaflor Mar 4, 2024
d7a6a83
Update
buenaflor Mar 4, 2024
cde560f
Update
buenaflor Mar 4, 2024
f66206d
remove import
buenaflor Mar 4, 2024
87d2755
Merge branch 'main' into feat/ttid
buenaflor Mar 4, 2024
4dedf37
Update sentry tracer
buenaflor Mar 4, 2024
5dd824e
Add (not all) improvements for pr review
buenaflor Mar 5, 2024
bf2ad2f
combine transaction handler
buenaflor Mar 5, 2024
4d33aab
Refactor trackAppStart and trackRegularRoute to use private method
buenaflor Mar 5, 2024
248cb8f
Fix dart analyzer
buenaflor Mar 5, 2024
35ec31c
Remove clear
buenaflor Mar 5, 2024
e1fde58
Clear in tearDown
buenaflor Mar 5, 2024
4efd9f9
Apply suggestions from code review
buenaflor Mar 5, 2024
579a3c5
Apply PR suggestions
buenaflor Mar 5, 2024
f2ba992
fix analyze
buenaflor Mar 5, 2024
7c64a3f
update
buenaflor Mar 5, 2024
d90a7ed
update
buenaflor Mar 5, 2024
b2767aa
Fix tests
buenaflor Mar 5, 2024
4c6301a
Fix analyze
buenaflor Mar 5, 2024
eaa6d8d
revert sample
buenaflor Mar 5, 2024
6ca06dd
Update
buenaflor Mar 5, 2024
c73de7b
Update
buenaflor Mar 5, 2024
caa9897
Fix child timestamp trimming
buenaflor Mar 5, 2024
438c8a2
Update CHANGELOG
buenaflor Mar 5, 2024
c4def3a
Run formatting
buenaflor Mar 5, 2024
bbb60ec
Update docs
buenaflor Mar 5, 2024
f9baa71
Revert
buenaflor Mar 5, 2024
238995e
Fix test
buenaflor Mar 6, 2024
133e166
Move clear to the beginning of function
buenaflor Mar 6, 2024
75a5eee
Merge branch 'fix/child-span-trimming' into feat/ttfd
buenaflor Mar 6, 2024
e50d7c5
initial commit
buenaflor Mar 6, 2024
cc4398d
Fix start time
buenaflor Mar 6, 2024
c0f41d8
Fix analyze
buenaflor Mar 6, 2024
2dafed4
Merge branch 'main' into feat/ttid
buenaflor Mar 6, 2024
7434ca1
remove comment
buenaflor Mar 6, 2024
e0298fe
Formatting
buenaflor Mar 6, 2024
b799120
Merge branch 'feat/ttid' into feat/ttfd
buenaflor Mar 6, 2024
897b4f5
update
buenaflor Mar 6, 2024
7e8478c
fix test
buenaflor Mar 6, 2024
f1a2740
Merge branch 'feat/ttid' into feat/ttfd
buenaflor Mar 6, 2024
a530fc3
Add changelog
buenaflor Mar 6, 2024
b99510a
Update
buenaflor Mar 6, 2024
532fcc4
Update
buenaflor Mar 6, 2024
969b578
fix analyze
buenaflor Mar 6, 2024
0b12c80
fix tests
buenaflor Mar 6, 2024
5ff7c0f
formatting
buenaflor Mar 6, 2024
67c6e8f
add ttid duration assertion and determineEndTime timeout
buenaflor Mar 6, 2024
d32bdea
Merge branch 'main' into feat/ttid
buenaflor Mar 6, 2024
320f92b
Rename finish transaction and do an early exit with enableAutoTransac…
buenaflor Mar 6, 2024
a823366
Rename function
buenaflor Mar 6, 2024
1cd1025
Merge branch 'main' into feat/ttid
buenaflor Mar 6, 2024
8dbe4ba
Merge branch 'feat/ttid' into feat/ttfd
buenaflor Mar 6, 2024
dbc4320
Remove static and getter for in navigator observer
buenaflor Mar 7, 2024
9c6e2b1
Expose SentryDisplayWidget as public api and add it to example app
buenaflor Mar 7, 2024
1aa2343
Fix dart analyze
buenaflor Mar 7, 2024
b15eccf
Fix dart doc
buenaflor Mar 7, 2024
b122a49
Merge branch 'feat/ttid' into feat/ttfd
buenaflor Mar 7, 2024
a7bb055
Get display tracker as static for reportFullyDisplayed()
buenaflor Mar 7, 2024
f9a34d7
Add @internal
buenaflor Mar 7, 2024
62e4e54
Fix test
buenaflor Mar 7, 2024
aeaebfa
Improve tests
buenaflor Mar 7, 2024
5552732
Reduce fake frame finishing time and improve tests
buenaflor Mar 7, 2024
524935c
Improve test names
buenaflor Mar 7, 2024
6e86523
Fix tests
buenaflor Mar 7, 2024
5fa126e
Apply formatting
buenaflor Mar 7, 2024
d209276
Add extra assertion in tests
buenaflor Mar 7, 2024
66b310b
Merge branch 'feat/ttid' into feat/ttfd
buenaflor Mar 7, 2024
2d16c67
Improve
buenaflor Mar 7, 2024
a0505c1
Use utc date time
buenaflor Mar 7, 2024
b203653
Fix test
buenaflor Mar 7, 2024
a353de2
Fix dartdoc
buenaflor Mar 7, 2024
e775c09
Update test
buenaflor Mar 7, 2024
7456eef
Update test
buenaflor Mar 7, 2024
7420ca4
Merge branch 'main' into feat/ttfd
buenaflor Mar 7, 2024
d1ff7f6
Merge branch 'main' into feat/ttfd
buenaflor Mar 7, 2024
9fdc8e2
Fix tests
buenaflor Mar 7, 2024
1b23622
Fix changelog
buenaflor Mar 7, 2024
dcbc1e6
Update
buenaflor Mar 8, 2024
b19f95c
Improve
buenaflor Mar 8, 2024
73022e4
Update
buenaflor Mar 8, 2024
10b0b93
Improve tests
buenaflor Mar 8, 2024
3085394
Update
buenaflor Mar 8, 2024
8548050
Change function to private
buenaflor Mar 8, 2024
a269ec8
Update CHANGELOG.md
buenaflor Mar 8, 2024
671ed7d
Rename function
buenaflor Mar 8, 2024
c6a8b27
add improvements (not all)
buenaflor Mar 11, 2024
bc18524
Fix tests
buenaflor Mar 11, 2024
e422ae4
Merge branch 'main' into feat/ttfd
buenaflor Mar 11, 2024
d4f3d88
Update changelog
buenaflor Mar 11, 2024
cb95c14
Finish after setting scope span to null
buenaflor Mar 11, 2024
a809130
update
buenaflor Mar 11, 2024
788eed7
updaet
buenaflor Mar 11, 2024
335528f
update
buenaflor Mar 11, 2024
b4ce9ef
clear first in didPush
buenaflor Mar 11, 2024
a210151
update
buenaflor Mar 11, 2024
d32a735
Merge branch 'main' into feat/ttfd
buenaflor Mar 11, 2024
0fd5c7f
Merge branch 'main' into feat/ttfd
buenaflor Mar 12, 2024
dfd36b6
update example
buenaflor Mar 12, 2024
6ae7df1
Merge branch 'main' into feat/ttfd
buenaflor Mar 12, 2024
7ee807a
add improvements
buenaflor Mar 12, 2024
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
29 changes: 17 additions & 12 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
# Changelog

## Unreleased

## Features

- Add TTFD (time to full display), which allows you to measure the time it takes to render the full screen ([#1920](https://github.com/getsentry/sentry-dart/pull/1920))
- Requires using the [routing instrumentation](https://docs.sentry.io/platforms/flutter/integrations/routing-instrumentation/).
- Set `enableTimeToFullDisplayTracing = true` in your `SentryFlutterOptions` to enable TTFD
- Manually report the end of the full display by calling `SentryFlutter.reportFullyDisplayed()`
- If not reported within 30 seconds, the span will be automatically finish with the status `deadline_exceeded`
- Add TTID (time to initial display), which allows you to measure the time it takes to render the first frame of your screen ([#1910](https://github.com/getsentry/sentry-dart/pull/1910))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is TTID not released, yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

craft messed up the merging. I merged the ttid pr during the release of 7.17.0 so craft merged the changelog together in a wrong way when the release finished - but it's not included in the release changelog so all good

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can release it together with ttfd on 7.18.0 this week

- Requires using the [routing instrumentation](https://docs.sentry.io/platforms/flutter/integrations/routing-instrumentation/).
- Introduces two modes:
- `automatic` mode is enabled by default for all screens and will yield only an approximation result.
- `manual` mode requires manual instrumentation and will yield a more accurate result.
- To use `manual` mode, you need to wrap your desired widget: `SentryDisplayWidget(child: MyScreen())`.
- You can mix and match both modes in your app.
- Other significant fixes
- `didPop` doesn't trigger a new transaction
- Change transaction operation name to `ui.load` instead of `navigation`
- Add override `captureFailedRequests` option ([#1931](https://github.com/getsentry/sentry-dart/pull/1931))
- The `dio` integration and `SentryHttpClient` now take an additional `captureFailedRequests` option.
- This is useful if you want to disable this option on native and only enable it on `dio` for example.
Expand All @@ -23,17 +38,7 @@
- remove transitive dart:io reference for web ([#1898](https://github.com/getsentry/sentry-dart/pull/1898))

### Features

- Add TTID (time to initial display), which allows you to measure the time it takes to render the first frame of your screen ([#1910](https://github.com/getsentry/sentry-dart/pull/1910))
- Requires using the [routing instrumentation](https://docs.sentry.io/platforms/flutter/integrations/routing-instrumentation/).
- Introduces two modes:
- `automatic` mode is enabled by default for all screens and will yield only an approximation result.
- `manual` mode requires manual instrumentation and will yield a more accurate result.
- To use `manual` mode, you need to wrap your desired widget: `SentryDisplayWidget(child: MyScreen())`.
- You can mix and match both modes in your app.
- Other significant fixes
- `didPop` doesn't trigger a new transaction
- Change transaction operation name to `ui.load` instead of `navigation`
-
- Use `recordHttpBreadcrumbs` to set iOS `enableNetworkBreadcrumbs` ([#1884](https://github.com/getsentry/sentry-dart/pull/1884))
- Apply `beforeBreadcrumb` on native iOS crumbs ([#1914](https://github.com/getsentry/sentry-dart/pull/1914))
- Add `maxQueueSize` to limit the number of unawaited events sent to Sentry ([#1868](https://github.com/getsentry/sentry-dart/pull/1868))
Expand Down
7 changes: 7 additions & 0 deletions dart/lib/src/sentry_measurement.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ class SentryMeasurement {
value = duration.inMilliseconds,
unit = DurationSentryMeasurementUnit.milliSecond;

/// Duration of the time to full display in milliseconds
SentryMeasurement.timeToFullDisplay(Duration duration)
: assert(!duration.isNegative),
name = 'time_to_full_display',
value = duration.inMilliseconds,
unit = DurationSentryMeasurementUnit.milliSecond;

final String name;
final num value;
final SentryMeasurementUnit? unit;
Expand Down
1 change: 1 addition & 0 deletions dart/lib/src/sentry_span_operations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ import 'package:meta/meta.dart';
class SentrySpanOperations {
static const String uiLoad = 'ui.load';
static const String uiTimeToInitialDisplay = 'ui.load.initial_display';
static const String uiTimeToFullDisplay = 'ui.load.full_display';
}
1 change: 1 addition & 0 deletions dart/test/sentry_tracer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ void main() {
test('end trimmed to latest child end timestamp', () async {
final sut = fixture.getSut(trimEnd: true);
final rootEndInitial = getUtcDateTime();

final childAEnd = rootEndInitial;
final childBEnd = rootEndInitial.add(Duration(seconds: 1));
final childCEnd = rootEndInitial;
Expand Down
18 changes: 13 additions & 5 deletions flutter/example/lib/auto_close_screen.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:sentry/sentry.dart';
import 'package:sentry_dio/sentry_dio.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

import 'main.dart';

/// This screen is only used to demonstrate how route navigation works.
/// Init will create a child span and pop the screen after 3 seconds.
Expand All @@ -21,11 +25,15 @@
}

Future<void> _doComplexOperationThenClose() async {
final activeSpan = Sentry.getSpan();

Check warning on line 28 in flutter/example/lib/auto_close_screen.dart

View workflow job for this annotation

GitHub Actions / analyze / analyze

The value of the local variable 'activeSpan' isn't used.

Try removing the variable or using it. See https://dart.dev/diagnostics/unused_local_variable to learn more about this problem.
final childSpan = activeSpan?.startChild('complex operation',
description: 'running a $delayInSeconds seconds operation');
await Future.delayed(const Duration(seconds: delayInSeconds));
childSpan?.finish();
final dio = Dio();
dio.addSentry();
try {
await dio.get<String>(exampleUrl);
} catch (exception, stackTrace) {
await Sentry.captureException(exception, stackTrace: stackTrace);
}
SentryFlutter.reportFullyDisplayed();
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
}
Expand Down
1 change: 1 addition & 0 deletions flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Future<void> setupSentry(
// configuration issues, e.g. finding out why your events are not uploaded.
options.debug = true;
options.spotlight = Spotlight(enabled: true);
options.enableTimeToFullDisplayTracing = true;

options.maxRequestBodySize = MaxRequestBodySize.always;
options.maxResponseBodySize = MaxResponseBodySize.always;
Expand Down
141 changes: 101 additions & 40 deletions flutter/lib/src/navigation/sentry_navigator_observer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import '../../sentry_flutter.dart';
import '../event_processor/flutter_enricher_event_processor.dart';
import '../native/sentry_native.dart';

// ignore: implementation_imports
import 'package:sentry/src/sentry_tracer.dart';

/// This key must be used so that the web interface displays the events nicely
/// See https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/
const _navigationKey = 'navigation';
Expand Down Expand Up @@ -82,11 +85,23 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
_setRouteNameAsTransaction = setRouteNameAsTransaction,
_routeNameExtractor = routeNameExtractor,
_additionalInfoProvider = additionalInfoProvider,
_native = SentryFlutter.native,
_timeToDisplayTracker = timeToDisplayTracker ?? TimeToDisplayTracker() {
_native = SentryFlutter.native {
if (enableAutoTransactions) {
_hub.options.sdk.addIntegration('UINavigationTracing');
}
_timeToDisplayTracker =
timeToDisplayTracker ?? _initializeTimeToDisplayTracker();
}

/// Initializes the TimeToDisplayTracker with the option to enable time to full display tracing.
TimeToDisplayTracker _initializeTimeToDisplayTracker() {
bool enableTimeToFullDisplayTracing = false;
final options = _hub.options;
if (options is SentryFlutterOptions) {
enableTimeToFullDisplayTracing = options.enableTimeToFullDisplayTracing;
}
return TimeToDisplayTracker(
enableTimeToFullDisplayTracing: enableTimeToFullDisplayTracing);
}

final Hub _hub;
Expand All @@ -96,7 +111,11 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
final RouteNameExtractor? _routeNameExtractor;
final AdditionalInfoExtractor? _additionalInfoProvider;
final SentryNative? _native;
final TimeToDisplayTracker? _timeToDisplayTracker;
static TimeToDisplayTracker? _timeToDisplayTracker;

@internal
static TimeToDisplayTracker? get timeToDisplayTracker =>
_timeToDisplayTracker;

ISentrySpan? _transaction;

Expand All @@ -105,7 +124,7 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
@internal
static String? get currentRouteName => _currentRouteName;

Completer<void>? _completedDisplayTracking;
Completer<void>? _completedDisplayTracking = Completer();

// Since didPush does not have a future, we can keep track of when the display tracking has finished
@visibleForTesting
Expand All @@ -124,6 +143,8 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
to: route.settings,
);

// Clearing the display tracker here is safe since didPush happens before the Widget is built
_timeToDisplayTracker?.clear();
_finishTimeToDisplayTracking();
_startTimeToDisplayTracking(route);
}
Expand Down Expand Up @@ -155,7 +176,7 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
to: previousRoute?.settings,
);

_finishTimeToDisplayTracking();
_finishTimeToDisplayTracking(clearAfter: true);
}

void _addBreadcrumb({
Expand Down Expand Up @@ -253,56 +274,96 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
await _native?.beginNativeFramesCollection();
}

Future<void> _finishTimeToDisplayTracking() async {
_timeToDisplayTracker?.clear();

Future<void> _finishTimeToDisplayTracking({bool clearAfter = false}) async {
final transaction = _transaction;
_transaction = null;
if (transaction == null || transaction.finished) {
return;
try {
_hub.configureScope((scope) {
if (scope.span == transaction) {
scope.span = null;
}
});

if (transaction == null || transaction.finished) {
return;
stefanosiano marked this conversation as resolved.
Show resolved Hide resolved
}

// Cancel unfinished TTID/TTFD spans, e.g this might happen if the user navigates
// away from the current route before TTFD or TTID is finished.
for (final child in (transaction as SentryTracer).children) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can't just finish all spans of the transaction, as we would finish the spans started by the user, too.
we should just finish TTID and TTFD (with status deadline_exceeded).
Also, we can remove the transaction from the scope and let it finish in the background. wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should just finish TTID and TTFD (with status deadline_exceeded)

👍

we can remove the transaction from the scope and let it finish in the background. wdyt?

I think that's fine, probably is better than forcefully finishing it

Copy link
Contributor Author

@buenaflor buenaflor Mar 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we remove it from the scope and still finish it without awaiting?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we remove it from the scope and still finish it without awaiting?

yep, that's the idea

final isTTIDSpan = child.context.operation ==
SentrySpanOperations.uiTimeToInitialDisplay;
final isTTFDSpan =
child.context.operation == SentrySpanOperations.uiTimeToFullDisplay;
if (!child.finished && (isTTIDSpan || isTTFDSpan)) {
await child.finish(status: SpanStatus.deadlineExceeded());
}
}
} catch (exception, stacktrace) {
_hub.options.logger(
SentryLevel.error,
'Error while finishing time to display tracking',
exception: exception,
stackTrace: stacktrace,
);
} finally {
await transaction?.finish();
if (clearAfter) {
_clear();
}
}
transaction.status ??= SpanStatus.ok();
await transaction.finish();
}

Future<void> _startTimeToDisplayTracking(Route<dynamic>? route) async {
if (!_enableAutoTransactions) {
return;
}
try {
final routeName = _getRouteName(route) ?? _currentRouteName;
if (!_enableAutoTransactions || routeName == null) {
return;
}

_completedDisplayTracking = Completer<void>();
String? routeName = _currentRouteName;
if (routeName == null) return;
bool isAppStart = routeName == '/';
DateTime startTimestamp = _hub.options.clock();
DateTime? endTimestamp;

DateTime startTimestamp = _hub.options.clock();
DateTime? endTimestamp;
if (isAppStart) {
final appStartInfo = await NativeAppStartIntegration.getAppStartInfo();
if (appStartInfo == null) return;

if (routeName == '/') {
final appStartInfo = await NativeAppStartIntegration.getAppStartInfo();
if (appStartInfo == null) {
return;
startTimestamp = appStartInfo.start;
endTimestamp = appStartInfo.end;
}

startTimestamp = appStartInfo.start;
endTimestamp = appStartInfo.end;
}
await _startTransaction(route, startTimestamp);

await _startTransaction(route, startTimestamp);
final transaction = _transaction;
if (transaction == null) {
return;
}
final transaction = _transaction;
if (transaction == null) {
return;
}

if (routeName == '/' && endTimestamp != null) {
await _timeToDisplayTracker?.trackAppStartTTD(transaction,
startTimestamp: startTimestamp, endTimestamp: endTimestamp);
} else {
await _timeToDisplayTracker?.trackRegularRouteTTD(transaction,
startTimestamp: startTimestamp);
if (isAppStart && endTimestamp != null) {
await _timeToDisplayTracker?.trackAppStartTTD(transaction,
startTimestamp: startTimestamp, endTimestamp: endTimestamp);
} else {
await _timeToDisplayTracker?.trackRegularRouteTTD(transaction,
startTimestamp: startTimestamp);
}
} catch (exception, stacktrace) {
_hub.options.logger(
SentryLevel.error,
'Error while tracking time to display',
exception: exception,
stackTrace: stacktrace,
);
} finally {
_clear();
}
}

// Mark the tracking as completed and clear any temporary state.
_completedDisplayTracking?.complete();
void _clear() {
if (_completedDisplayTracking?.isCompleted == false) {
_completedDisplayTracking?.complete();
}
_completedDisplayTracking = Completer();
_timeToDisplayTracker?.clear();
}
}
Expand Down
27 changes: 24 additions & 3 deletions flutter/lib/src/navigation/time_to_display_tracker.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
// ignore_for_file: invalid_use_of_internal_member

import 'dart:async';

import 'package:meta/meta.dart';

import '../../sentry_flutter.dart';
import 'time_to_full_display_tracker.dart';
import 'time_to_initial_display_tracker.dart';

@internal
class TimeToDisplayTracker {
final TimeToInitialDisplayTracker _ttidTracker;
final TimeToFullDisplayTracker? _ttfdTracker;
final bool enableTimeToFullDisplayTracing;

TimeToDisplayTracker({
TimeToInitialDisplayTracker? ttidTracker,
}) : _ttidTracker = ttidTracker ?? TimeToInitialDisplayTracker();
TimeToFullDisplayTracker? ttfdTracker,
required this.enableTimeToFullDisplayTracing,
}) : _ttidTracker = ttidTracker ?? TimeToInitialDisplayTracker(),
_ttfdTracker = enableTimeToFullDisplayTracing
? ttfdTracker ?? TimeToFullDisplayTracker()
: null;

Future<void> trackAppStartTTD(ISentrySpan transaction,
{required DateTime startTimestamp,
required DateTime endTimestamp}) async {
// We start and immediately finish the spans since we cannot mutate the history of spans.
await _ttidTracker.trackAppStart(transaction,
startTimestamp: startTimestamp, endTimestamp: endTimestamp);
await _trackTTFDIfEnabled(transaction, startTimestamp);
}

Future<void> trackRegularRouteTTD(ISentrySpan transaction,
{required DateTime startTimestamp}) async {
await _ttidTracker.trackRegularRoute(transaction, startTimestamp);
await _trackTTFDIfEnabled(transaction, startTimestamp);
}

Future<void> _trackTTFDIfEnabled(
ISentrySpan transaction, DateTime startTimestamp) async {
if (enableTimeToFullDisplayTracing) {
await _ttfdTracker?.track(transaction, startTimestamp);
}
}

@internal
Future<void> reportFullyDisplayed() async {
return _ttfdTracker?.reportFullyDisplayed();
}

void clear() {
_ttidTracker.clear();
_ttfdTracker?.clear();
}
}
Loading
Loading