Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
buenaflor committed Feb 8, 2024
1 parent 51d6c6d commit 4c976b3
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 36 deletions.
2 changes: 1 addition & 1 deletion flutter/example/lib/auto_close_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AutoCloseScreenState extends State<AutoCloseScreen> {
await childSpan?.finish();
SentryFlutter.reportFullDisplay();
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
// Navigator.of(context).pop();
}

@override
Expand Down
3 changes: 3 additions & 0 deletions flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Future<void> setupSentry(AppRunner appRunner, String dsn,
options.screenshotQuality = SentryScreenshotQuality.low;
options.attachViewHierarchy = true;
options.enableTimeToFullDisplayTracing = true;
options.spotlight = Spotlight(enabled: true);
// We can enable Sentry debug logging during development. This is likely
// going to log too much for your app, but can be useful when figuring out
// configuration issues, e.g. finding out why your events are not uploaded.
Expand Down Expand Up @@ -99,8 +100,10 @@ class MyApp extends StatefulWidget {
}

class _MyAppState extends State<MyApp> {

@override
Widget build(BuildContext context) {
SentryFlutter.reportFullDisplay();
return feedback.BetterFeedback(
child: ChangeNotifierProvider<ThemeProvider>(
create: (_) => ThemeProvider(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class NativeAppStartEventProcessor implements EventProcessor {
if (measurement.value >= _maxAppStartMillis) {
return event;
}
print('hello app');

event.measurements[measurement.name] = measurement;
}
return event;
Expand Down
65 changes: 64 additions & 1 deletion flutter/lib/src/integrations/native_app_start_integration.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/scheduler.dart';
import 'package:sentry/sentry.dart';

import '../../sentry_flutter.dart';
import '../sentry_flutter_options.dart';
import '../native/sentry_native.dart';
import '../event_processor/native_app_start_event_processor.dart';
Expand All @@ -21,9 +22,71 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
options.logger(SentryLevel.debug,
'Scheduler binding is null. Can\'t auto detect app start time.');
} else {
schedulerBinding.addPostFrameCallback((timeStamp) {
schedulerBinding.addPostFrameCallback((timeStamp) async {
// ignore: invalid_use_of_internal_member
_native.appStartEnd = options.clock();

final appStartEnd = _native.appStartEnd;

if (_native.appStartEnd != null && !_native!.didFetchAppStart) {
print('fetch app start');
final nativeAppStart = await _native!.fetchNativeAppStart();
if (nativeAppStart == null) {
return;
}
final measurement = nativeAppStart.toMeasurement(appStartEnd!);
// We filter out app start more than 60s.
// This could be due to many different reasons.
// If you do the manual init and init the SDK too late and it does not
// compute the app start end in the very first Screen.
// If the process starts but the App isn't in the foreground.
// If the system forked the process earlier to accelerate the app start.
// And some unknown reasons that could not be reproduced.
// We've seen app starts with hours, days and even months.
if (measurement.value >= 60000) {
return;
}

final appStartDateTime = DateTime.fromMillisecondsSinceEpoch(
nativeAppStart.appStartTime.toInt());

final transactionContext2 = SentryTransactionContext(
'root ("/")',
'ui.load',
transactionNameSource: SentryTransactionNameSource.component,
// ignore: invalid_use_of_internal_member
origin: SentryTraceOrigins.autoNavigationRouteObserver,
);

final transaction2 = hub.startTransactionWithContext(
transactionContext2,
waitForChildren: true,
autoFinishAfter: Duration(seconds: 3),
trimEnd: true,
startTimestamp: appStartDateTime,
onFinish: (transaction) async {
final nativeFrames = await _native
?.endNativeFramesCollection(transaction.context.traceId);
if (nativeFrames != null) {
final measurements = nativeFrames.toMeasurements();
for (final item in measurements.entries) {
final measurement = item.value;
transaction.setMeasurement(
item.key,
measurement.value,
unit: measurement.unit,
);
}
}
});

final ttidSpan = transaction2.startChild('ui.load.initial_display', startTimestamp: appStartDateTime);
await ttidSpan.finish(endTimestamp: appStartEnd);

SentryNavigatorObserver.ttfdSpan = transaction2.startChild('ui.load.full_display', startTimestamp: appStartDateTime);

print('end of the road');
}
});
}
}
Expand Down
75 changes: 42 additions & 33 deletions flutter/lib/src/navigation/sentry_navigator_observer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:meta/meta.dart';

import '../../sentry_flutter.dart';
import '../event_processor/flutter_enricher_event_processor.dart';
import '../event_processor/native_app_start_event_processor.dart';
import '../native/sentry_native.dart';

/// This key must be used so that the web interface displays the events nicely
Expand Down Expand Up @@ -127,19 +128,21 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
approximationEndTimestamp = DateTime.now();
approximationDurationMillis =
approximationEndTimestamp!.millisecondsSinceEpoch - startTime.millisecondsSinceEpoch;
approximationEndTimestamp!.millisecondsSinceEpoch -
startTime.millisecondsSinceEpoch;
});

SentryDisplayTracker().startTimeout(routeName ?? 'Unknown', () {
if (routeName == '/') {
// TODO: Does TTID have to be completely in line with app start?
// If yes, how do we access the appstart metrics
} else {
_transaction2?.setMeasurement(
'time_to_initial_display', approximationDurationMillis!,
unit: DurationSentryMeasurementUnit.milliSecond);
ttidSpan?.finish(endTimestamp: approximationEndTimestamp!);
print('finished already');
}
_transaction2?.setMeasurement(
'time_to_initial_display', approximationDurationMillis!,
unit: DurationSentryMeasurementUnit.milliSecond);
ttidSpan?.finish(endTimestamp: approximationEndTimestamp!);
print('finished already');
});
}

Expand Down Expand Up @@ -249,27 +252,31 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
origin: SentryTraceOrigins.autoNavigationRouteObserver,
);

_transaction2 = _hub.startTransactionWithContext(
transactionContext2,
waitForChildren: true,
autoFinishAfter: _autoFinishAfter,
trimEnd: true,
onFinish: (transaction) async {
final nativeFrames = await _native
?.endNativeFramesCollection(transaction.context.traceId);
if (nativeFrames != null) {
final measurements = nativeFrames.toMeasurements();
for (final item in measurements.entries) {
final measurement = item.value;
transaction.setMeasurement(
item.key,
measurement.value,
unit: measurement.unit,
);
if (name == 'root ("/")') {

} else {
_transaction2 = _hub.startTransactionWithContext(
transactionContext2,
waitForChildren: true,
autoFinishAfter: _autoFinishAfter,
trimEnd: true,
onFinish: (transaction) async {
final nativeFrames = await _native
?.endNativeFramesCollection(transaction.context.traceId);
if (nativeFrames != null) {
final measurements = nativeFrames.toMeasurements();
for (final item in measurements.entries) {
final measurement = item.value;
transaction.setMeasurement(
item.key,
measurement.value,
unit: measurement.unit,
);
}
}
}
},
);
},
);
}

// if _enableAutoTransactions is enabled but there's no traces sample rate
if (_transaction is NoOpSentrySpan) {
Expand All @@ -280,12 +287,13 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
if (name == 'root ("/")') {
// root ttid spans have to align with app start
// so the ttid instrumentation needs to be different here.
startTime = DateTime.now();
ttidSpan = _transaction2?.startChild('ui.load.initial_display', description: '$name initial display', startTimestamp: startTime);
ttidSpan?.origin = 'auto.ui.time_to_display';
// startTime = DateTime.now();
// ttidSpan = _transaction2?.startChild('ui.load.initial_display', description: '$name initial display', startTimestamp: startTime);
// ttidSpan?.origin = 'auto.ui.time_to_display';
} else {
startTime = DateTime.now();
ttidSpan = _transaction2?.startChild('ui.load.initial_display', description: '$name initial display', startTimestamp: startTime);
ttidSpan = _transaction2?.startChild('ui.load.initial_display',
description: '$name initial display', startTimestamp: startTime);
ttidSpan?.origin = 'auto.ui.time_to_display';
}

Expand All @@ -296,10 +304,11 @@ class SentryNavigatorObserver extends RouteObserver<PageRoute<dynamic>> {
//
// temporarily disable ttfd for root since it somehow swallows other spans
// e.g the complex operation span in autoclosescreen
if ((_hub.options as SentryFlutterOptions).enableTimeToFullDisplayTracing && name != 'root ("/")') {
ttfdStopwatch = Stopwatch()..start();
if ((_hub.options as SentryFlutterOptions).enableTimeToFullDisplayTracing &&
name != 'root ("/")') {
ttfdStartTime = DateTime.now();
ttfdSpan = _transaction2?.startChild('ui.load.full_display', description: '$name full display', startTimestamp: ttfdStartTime);
ttfdSpan = _transaction2?.startChild('ui.load.full_display',
description: '$name full display', startTimestamp: ttfdStartTime);
}

if (arguments != null) {
Expand Down
1 change: 1 addition & 0 deletions flutter/lib/src/sentry_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ mixin SentryFlutter {
/// Reports the time it took for the screen to be fully displayed.
static void reportFullDisplay() {
final endTime = DateTime.now();
print('end of the road2');
SentryNavigatorObserver.ttfdSpan?.setMeasurement(
'time_to_full_display',
endTime.millisecondsSinceEpoch - SentryNavigatorObserver.ttfdStartTime.millisecondsSinceEpoch,
Expand Down

0 comments on commit 4c976b3

Please sign in to comment.