Skip to content

Commit

Permalink
update poc
Browse files Browse the repository at this point in the history
  • Loading branch information
buenaflor committed Feb 9, 2024
1 parent 4c976b3 commit 75a76fc
Show file tree
Hide file tree
Showing 7 changed files with 402 additions and 114 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 @@ -27,7 +27,7 @@ class AutoCloseScreenState extends State<AutoCloseScreen> {
description: 'running a $delayInSeconds seconds operation');
await Future.delayed(const Duration(seconds: delayInSeconds));
await childSpan?.finish();
SentryFlutter.reportFullDisplay();
SentryFlutter.reportFullyDisplayed();
// ignore: use_build_context_synchronously
// Navigator.of(context).pop();
}
Expand Down
2 changes: 1 addition & 1 deletion flutter/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ class _MyAppState extends State<MyApp> {

@override
Widget build(BuildContext context) {
SentryFlutter.reportFullDisplay();
// SentryFlutter.reportFullDisplay();
return feedback.BetterFeedback(
child: ChangeNotifierProvider<ThemeProvider>(
create: (_) => ThemeProvider(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:async';

import 'package:sentry/sentry.dart';

import '../integrations/integrations.dart';
import '../native/sentry_native.dart';

/// EventProcessor that enriches [SentryTransaction] objects with app start
Expand All @@ -18,28 +19,9 @@ class NativeAppStartEventProcessor implements EventProcessor {

@override
Future<SentryEvent?> apply(SentryEvent event, {Hint? hint}) async {
final appStartEnd = _native.appStartEnd;

if (appStartEnd != null &&
event is SentryTransaction &&
!_native.didFetchAppStart) {
final nativeAppStart = await _native.fetchNativeAppStart();
if (nativeAppStart == null) {
return event;
}
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 >= _maxAppStartMillis) {
return event;
}

final appStartInfo = AppStartTracker().appStartInfo;
if (appStartInfo != null && event is SentryTransaction) {
final measurement = appStartInfo.measurement;
event.measurements[measurement.name] = measurement;
}
return event;
Expand Down
102 changes: 55 additions & 47 deletions flutter/lib/src/integrations/native_app_start_integration.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/scheduler.dart';
import 'package:meta/meta.dart';
import 'package:sentry/sentry.dart';

import '../../sentry_flutter.dart';
Expand All @@ -23,18 +24,14 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
'Scheduler binding is null. Can\'t auto detect app start time.');
} else {
schedulerBinding.addPostFrameCallback((timeStamp) async {
final appStartEnd = options.clock();
// ignore: invalid_use_of_internal_member
_native.appStartEnd = options.clock();
_native.appStartEnd = appStartEnd;

final appStartEnd = _native.appStartEnd;
if (!_native.didFetchAppStart) {
final nativeAppStart = await _native.fetchNativeAppStart();
final measurement = nativeAppStart?.toMeasurement(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
Expand All @@ -43,49 +40,23 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
// 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) {
if (nativeAppStart == null ||
measurement == null ||
measurement.value >= 60000) {
AppStartTracker().setAppStartInfo(null);
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 appStartInfo = AppStartInfo(
DateTime.fromMillisecondsSinceEpoch(
nativeAppStart.appStartTime.toInt()),
appStartEnd,
measurement,
);

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');
AppStartTracker().setAppStartInfo(appStartInfo);
} else {
AppStartTracker().setAppStartInfo(null);
}
});
}
Expand All @@ -99,3 +70,40 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {

/// Used to provide scheduler binding at call time.
typedef SchedulerBindingProvider = SchedulerBinding? Function();

@internal
class AppStartInfo {
final DateTime start;
final DateTime end;
final SentryMeasurement measurement;

AppStartInfo(this.start, this.end, this.measurement);
}

@internal
class AppStartTracker {
static final AppStartTracker _instance = AppStartTracker._internal();

factory AppStartTracker() => _instance;

AppStartInfo? _appStartInfo;

AppStartInfo? get appStartInfo => _appStartInfo;
Function(AppStartInfo?)? _callback;

AppStartTracker._internal();

void setAppStartInfo(AppStartInfo? appStartInfo) {
_appStartInfo = appStartInfo;
_notifyObserver();
}

void onAppStartComplete(Function(AppStartInfo?) callback) {
_callback = callback;
_callback?.call(_appStartInfo);
}

void _notifyObserver() {
_callback?.call(_appStartInfo);
}
}
Loading

0 comments on commit 75a76fc

Please sign in to comment.