Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
5ad308b
commit
buenaflor Apr 18, 2024
7bc756b
Merge branch 'main' into feat/app-start-improve
buenaflor Apr 23, 2024
3e0790a
Update
buenaflor Apr 23, 2024
d0eb540
Remove print
buenaflor Apr 23, 2024
05c208c
Remove comments
buenaflor Apr 23, 2024
c796b71
Update
buenaflor Apr 24, 2024
da8297e
Merge branch 'main' into feat/app-start-improve
buenaflor Apr 24, 2024
bdc8588
Add linting
buenaflor Apr 24, 2024
d1b37cd
Update CHANGELOG
buenaflor Apr 24, 2024
6f44478
Update CHANGELOG.md
buenaflor Apr 24, 2024
8051972
Update naming
buenaflor Apr 24, 2024
29671ff
Merge branch 'main' into feat/app-start-improve
buenaflor Apr 24, 2024
b401ed0
Update naming
buenaflor Apr 24, 2024
c06973c
Update naming
buenaflor Apr 24, 2024
2bb3887
Update description from first frame render to initial frame render
buenaflor Apr 24, 2024
3aadc19
Initial
buenaflor Apr 25, 2024
86bc3bf
Merge branch 'feat/app-start-improve' into feat/app-start-native-spans
buenaflor Apr 25, 2024
801483e
update
buenaflor Apr 26, 2024
d28af71
dart format
buenaflor Apr 26, 2024
21c61a6
Update comments
buenaflor Apr 26, 2024
88a8819
Update
buenaflor Apr 26, 2024
0d73052
Update
buenaflor Apr 26, 2024
1e05ae5
Update
buenaflor Apr 26, 2024
73d830a
Update
buenaflor Apr 26, 2024
62cb2be
Update
buenaflor Apr 26, 2024
111125c
Fix tests
buenaflor Apr 29, 2024
04ad023
Fix test
buenaflor Apr 29, 2024
e9e95c4
Add unused import
buenaflor Apr 29, 2024
bb785b6
Merge branch 'feat/app-start-improve' into feat/app-start-native-spans
buenaflor Apr 29, 2024
d0ce3a4
Fix tests
buenaflor Apr 29, 2024
b22a9c0
Update
buenaflor May 2, 2024
d4c6b1a
Updaet
buenaflor May 2, 2024
06325a2
Update
buenaflor May 3, 2024
bc7ba9e
Update
buenaflor May 3, 2024
4367089
Merge branch 'main' into feat/app-start-native-spans
buenaflor May 6, 2024
a847325
Update CHANGELOG
buenaflor May 6, 2024
7703c4e
Update CHANGELOG
buenaflor May 6, 2024
4ae3212
Update formatting of kotlin file
buenaflor May 6, 2024
342b518
Update
buenaflor May 6, 2024
7a1084f
Update test
buenaflor May 6, 2024
16303bd
format
buenaflor May 6, 2024
20e595f
Update SentryFlutterPlugin.kt
buenaflor May 6, 2024
0cf5d12
Update SentryFlutterPlugin.kt
buenaflor May 6, 2024
2820fc8
Update
buenaflor May 6, 2024
c122240
Update main.dart
buenaflor May 6, 2024
939ed17
Merge branch 'main' into feat/app-start-native-spans
buenaflor May 8, 2024
cdad9a8
Update
buenaflor May 8, 2024
ffb3695
Update
buenaflor May 8, 2024
e3197a7
Update
buenaflor May 8, 2024
427d516
Updaet
buenaflor May 8, 2024
ab63c3b
Format
buenaflor May 8, 2024
93b4516
Update flutter/lib/src/sentry_flutter.dart
buenaflor May 9, 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
Prev Previous commit
Next Next commit
Update
  • Loading branch information
buenaflor committed Apr 24, 2024
commit c796b7172e9e22ca15e7c7e3f5c8c91cef264cfb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: invalid_use_of_internal_member

import 'dart:async';

import '../../sentry_flutter.dart';
Expand Down Expand Up @@ -78,7 +80,7 @@ class NativeAppStartEventProcessor implements EventProcessor {
description: 'First frame render',
parentSpanId: appStartSpan.context.spanId,
traceId: transactionTraceId,
startTimestamp: SentryFlutter.dartLoadingEnd!,
startTimestamp: SentryFlutter.dartLoadingEnd,
endTimestamp: appStartInfo.end);

transaction.children.addAll([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
final appStartEnd = _native.appStartEnd;
final nativeAppStart = await _native.fetchNativeAppStart();
final engineEndtime = await _native.fetchEngineEndtime();
final dartLoadingEnd = SentryFlutter.dartLoadingEnd;

if (nativeAppStart == null ||
appStartEnd == null ||
Expand Down Expand Up @@ -104,7 +105,8 @@ class NativeAppStartIntegration extends Integration<SentryFlutterOptions> {
nativeAppStart.appStartTime.toInt()),
end: appStartEnd,
engineEnd: engineEndDatetime,
dartLoadingEnd: SentryFlutter.dartLoadingEnd!);
dartLoadingEnd: dartLoadingEnd);

setAppStartInfo(appStartInfo);
});
}
Expand Down
5 changes: 4 additions & 1 deletion flutter/lib/src/sentry_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ typedef FlutterOptionsConfiguration = FutureOr<void> Function(
mixin SentryFlutter {
static const _channel = MethodChannel('sentry_flutter');

/// Represents the time when the dart isolate stopped loading and is ready to execute.
@internal
static DateTime? dartLoadingEnd;
// ignore: invalid_use_of_internal_member
static DateTime dartLoadingEnd = getUtcDateTime();

static Future<void> init(
FlutterOptionsConfiguration optionsConfiguration, {
Expand All @@ -46,6 +48,7 @@ mixin SentryFlutter {
}) async {
final flutterOptions = SentryFlutterOptions();

// ignore: invalid_use_of_internal_member
dartLoadingEnd = flutterOptions.clock();

if (platformChecker != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@TestOn('vm')
import 'package:collection/collection.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
Expand Down Expand Up @@ -109,6 +110,100 @@ void main() {
expect(appStartInfo?.end, DateTime.fromMillisecondsSinceEpoch(10));
});
});

group('App start spans', () {
late SentrySpan? coldStartSpan,
engineReadySpan,
dartIsolateLoadingSpan,
firstFrameRenderSpan;
// ignore: invalid_use_of_internal_member
late SentryTracer tracer;
late Fixture fixture;

setUp(() async {
TestWidgetsFlutterBinding.ensureInitialized();

fixture = Fixture();
NativeAppStartIntegration.clearAppStartInfo();

fixture.native.appStartEnd = DateTime.fromMillisecondsSinceEpoch(50);
fixture.binding.nativeAppStart = NativeAppStart(0, true);
// dartLoadingEnd needs to be set after engine end (see MockNativeChannel)
SentryFlutter.dartLoadingEnd = DateTime.fromMillisecondsSinceEpoch(15);

fixture.getNativeAppStartIntegration().call(fixture.hub, fixture.options);

final processor = fixture.options.eventProcessors.first;
tracer = fixture.createTracer();
final transaction = SentryTransaction(tracer);
final enriched =
await processor.apply(transaction, Hint()) as SentryTransaction;

coldStartSpan = enriched.spans.firstWhereOrNull(
(element) => element.context.description == 'Cold start');
engineReadySpan = enriched.spans.firstWhereOrNull(
(element) => element.context.description == 'Engine init and ready');
dartIsolateLoadingSpan = enriched.spans.firstWhereOrNull(
(element) => element.context.description == 'Dart isolate loading');
firstFrameRenderSpan = enriched.spans.firstWhereOrNull(
(element) => element.context.description == 'First frame render');
});

test('are added by event processor', () async {
expect(coldStartSpan, isNotNull);
expect(engineReadySpan, isNotNull);
expect(dartIsolateLoadingSpan, isNotNull);
expect(firstFrameRenderSpan, isNotNull);
});

test('have correct op', () async {
const op = 'app.start.cold';
expect(coldStartSpan?.context.operation, op);
expect(engineReadySpan?.context.operation, op);
expect(dartIsolateLoadingSpan?.context.operation, op);
expect(firstFrameRenderSpan?.context.operation, op);
});

test('have correct parents', () async {
expect(coldStartSpan?.context.parentSpanId, tracer.context.spanId);
expect(
engineReadySpan?.context.parentSpanId, coldStartSpan?.context.spanId);
expect(dartIsolateLoadingSpan?.context.parentSpanId,
coldStartSpan?.context.spanId);
expect(firstFrameRenderSpan?.context.parentSpanId,
coldStartSpan?.context.spanId);
});

test('have correct traceId', () async {
final traceId = tracer.context.traceId;
expect(coldStartSpan?.context.traceId, traceId);
expect(engineReadySpan?.context.traceId, traceId);
expect(dartIsolateLoadingSpan?.context.traceId, traceId);
expect(firstFrameRenderSpan?.context.traceId, traceId);
});

test('have correct startTimestamp', () async {
final appStartTime = DateTime.fromMillisecondsSinceEpoch(
fixture.binding.nativeAppStart!.appStartTime.toInt())
.toUtc();
expect(coldStartSpan?.startTimestamp, appStartTime);
expect(engineReadySpan?.startTimestamp, appStartTime);
expect(dartIsolateLoadingSpan?.startTimestamp,
engineReadySpan?.endTimestamp);
expect(firstFrameRenderSpan?.startTimestamp,
dartIsolateLoadingSpan?.endTimestamp);
});

test('have correct endTimestamp', () async {
final engineEndtime = await fixture.native.fetchEngineEndtime();
expect(coldStartSpan?.endTimestamp, fixture.native.appStartEnd?.toUtc());
expect(engineReadySpan?.endTimestamp,
DateTime.fromMillisecondsSinceEpoch(engineEndtime!).toUtc());
expect(dartIsolateLoadingSpan?.endTimestamp,
SentryFlutter.dartLoadingEnd.toUtc());
expect(firstFrameRenderSpan?.endTimestamp, coldStartSpan?.endTimestamp);
});
});
}

class Fixture {
Expand Down
10 changes: 10 additions & 0 deletions flutter/test/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,11 @@ class TestMockSentryNative implements SentryNative {
numberOfDiscardProfilerCalls++;
return Future.value(null);
}

@override
Future<int?> fetchEngineEndtime() {
return Future.value(10);
}
}

// TODO can this be replaced with https://pub.dev/packages/mockito#verifying-exact-number-of-invocations--at-least-x--never
Expand Down Expand Up @@ -395,6 +400,11 @@ class MockNativeChannel implements SentryNativeBinding {
numberOfDiscardProfilerCalls++;
return Future.value(null);
}

@override
Future<int?> fetchEngineEndtime() {
return Future.value(10);
}
}

class MockRendererWrapper implements RendererWrapper {
Expand Down
2 changes: 2 additions & 0 deletions flutter/test/navigation/sentry_display_widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ void main() {
AppStartType.cold,
start: getUtcDateTime().add(Duration(seconds: 1)),
end: getUtcDateTime().add(Duration(seconds: 2)),
engineEnd: getUtcDateTime().add(Duration(seconds: 3)),
dartLoadingEnd: getUtcDateTime().add(Duration(seconds: 4)),
);
NativeAppStartIntegration.setAppStartInfo(appStartInfo);

Expand Down
2 changes: 2 additions & 0 deletions flutter/test/sentry_navigator_observer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,8 @@ void main() {
AppStartType.cold,
start: DateTime.now().add(const Duration(seconds: 1)),
end: DateTime.now().add(const Duration(seconds: 2)),
engineEnd: DateTime.now().add(const Duration(seconds: 3)),
dartLoadingEnd: DateTime.now().add(const Duration(seconds: 4)),
),
);

Expand Down