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: Mobile Vitals - Native Frames #772

Merged
merged 102 commits into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from 90 commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
bf37eb6
add sample call to android
Feb 2, 2022
4e7f0d5
sample call in ios plugin
Feb 2, 2022
fcce8ab
fetch app start state from android
Feb 2, 2022
5a25a53
Sync tracesSampleRate to native layer
Feb 3, 2022
7fafb1d
Add measuments and native app start call
Feb 3, 2022
c583ac8
Merge branch 'main' into feat/mobile-vitals-native-app-start
Feb 9, 2022
fbe8faa
add sample app start duration as measutrement to transaction
Feb 9, 2022
67b6528
Move out to own method
Feb 9, 2022
b6b649c
add measurements before scope assignment
Feb 9, 2022
a243a9a
Assume initial if there is no previous route
Feb 10, 2022
b2d3f81
sync tracesSampleRate
Feb 10, 2022
42df627
fix analyze issues
Feb 10, 2022
795c766
instrument after route navigation, fix native integration test
Feb 10, 2022
437c10c
add changelog entry
Feb 10, 2022
cec6d23
remove unneccessary semicolons
Feb 10, 2022
e5c80c6
remove didFetchAppStart from native side
Feb 16, 2022
9bec2cc
Merge branch 'main' into feat/mobile-vitals-native-app-start
Feb 16, 2022
003f498
move native app start instrumentation to MobileVitalsIntegration
Feb 16, 2022
43296ae
run format
Feb 16, 2022
68fc08b
add tests and cleanup
Feb 16, 2022
9f4805d
Only install mobile vitals integration for ios, macos and android
Feb 17, 2022
d9517fc
implement android flutter plugin for native frames
Feb 23, 2022
403ba49
add fetchNativeFrames to native wrapper
Feb 23, 2022
417b423
red from apple platforms
Feb 23, 2022
5108b46
impl first approach at measuring native frames
Feb 24, 2022
291d28d
rename property
Mar 2, 2022
9ba65f7
remove unused prop
Mar 2, 2022
9f17f88
remove trailing comma
Mar 2, 2022
0393b05
Merge branch 'main' into feat/mobile-vitals-native-app-start
Mar 2, 2022
f2ea0e0
remove sync of tracesSampleRate to native
Mar 2, 2022
ec8b54e
move mobile vitals integration to own file
Mar 2, 2022
5ac6031
inject scheduler binding instance
Mar 2, 2022
fc86d2a
move appStartEnd to own state class
Mar 3, 2022
89322c2
Fix unit test
Mar 3, 2022
f2306cd
return nil in ios integration, scheduler binding provider
Mar 3, 2022
b6ba8fa
Merge branch 'feat/mobile-vitals-native-app-start' into feat/mobile-v…
Mar 3, 2022
c7625a3
Merge branch 'main' into feat/mobile-vitals-native-app-start
Mar 9, 2022
14b30b4
log error kotlin plugin and return null success
Mar 9, 2022
6c458a3
Use android log
Mar 9, 2022
6b7232e
print warning on ios
Mar 9, 2022
12190f0
introduce shared instance
Mar 9, 2022
925bf2a
Merge branch 'feat/mobile-vitals-native-app-start' into feat/mobile-v…
Mar 9, 2022
c95efef
Bump sentry-android to 5.6.2
Mar 9, 2022
b4f8641
use ActivityFramesTracker to track frames
Mar 9, 2022
4fb7935
move data to SentryNativeState
Mar 9, 2022
e05deb0
add commnets
Mar 9, 2022
8f4c8a7
make constructor private
Mar 10, 2022
bfb02f3
append measurements
Mar 10, 2022
07e4229
public factory which returns singleton for SentryNativeState
marandaneto Mar 10, 2022
7443d0f
calculate frames
Mar 10, 2022
761cffd
fix compiler issues
Mar 10, 2022
b508e16
Bump sentry-cocoa to 7.10.1
Mar 10, 2022
a65da6c
implement class to native side
Mar 10, 2022
82ae0de
Merge branch 'feat/mobile-vitals-native-app-start' into feat/mobile-v…
Mar 10, 2022
c9fbf06
rename SentryNativeWrapper to SentryNativeChannel
Mar 10, 2022
852658a
revert file
Mar 10, 2022
395cbbc
cleanup
Mar 10, 2022
1190b5f
move NativeAppStartEventProcessor to own file
Mar 10, 2022
50206a8
Merge branch 'main' into feat/mobile-vitals-native-app-start
marandaneto Mar 11, 2022
d563537
introduce OnTransactionFinish callback
Mar 11, 2022
274239b
use weak ref for activity
Mar 11, 2022
1bf0ce7
null framesTracker
Mar 11, 2022
2149209
heck for zero frames
Mar 11, 2022
84982ee
return future
Mar 11, 2022
7c0cdc9
check zero values
Mar 11, 2022
41964ff
move native frame collection out of processor
Mar 11, 2022
6ef2cfb
Merge branch 'feat/mobile-vitals-native-app-start' into feat/mobile-v…
Mar 11, 2022
0afdbf9
format & fix analyze issues
Mar 11, 2022
b35bfb6
rename method
Mar 11, 2022
d2a3530
fix navigagtor observer tests
Mar 11, 2022
3564bf0
Merge branch 'feat/mobile-vitals' into feat/mobile-vitals-native-app-…
Mar 11, 2022
7af43db
introduce enableAutoPerformanceTracking flag
Mar 11, 2022
445fed0
Merge branch 'feat/mobile-vitals-native-app-start' into feat/mobile-v…
Mar 11, 2022
2309ac6
use toUTC() for app start end
Mar 11, 2022
57ff7ef
fix warnings in kotlin plugin
Mar 11, 2022
8b4b38b
fix swift plugin warnings
Mar 11, 2022
00d6d58
remove debug code
Mar 11, 2022
c6b0f22
rename integration
Mar 11, 2022
dd22858
renamings
Mar 11, 2022
e34d67d
rename file
Mar 11, 2022
b45b5b2
Merge branch 'feat/mobile-vitals-native-app-start' into feat/mobile-v…
Mar 11, 2022
dceb943
fix merge
Mar 11, 2022
d1c7321
Update changelog
Mar 11, 2022
cb15a58
Merge branch 'feat/mobile-vitals' into feat/mobile-vitial-native-frames
Mar 16, 2022
88c3bf4
incorporate pr feedback
Mar 16, 2022
6981a9f
Provide the native channel through method injection.
Mar 16, 2022
8b7c4d5
fix typo
Mar 16, 2022
1ff8d90
fix compile issues
Mar 16, 2022
9514f09
fix broken unit tests
Mar 16, 2022
b87fa59
Update flutter/android/build.gradle
marandaneto Mar 17, 2022
b90890e
Update CHANGELOG.md
marandaneto Mar 17, 2022
a385719
use singleton directly
Mar 17, 2022
a826e80
add tests for SentryNative
Mar 17, 2022
35cbdd4
add tests for SentryNativeChannel
Mar 17, 2022
9f27b9e
remove cp error
Mar 17, 2022
dddb90b
only one early return
Mar 17, 2022
fedf355
only execute frames tracking on ios targets
Mar 17, 2022
662ea5a
Enable frames tracking for macCatalyst
Mar 17, 2022
6b92b8c
pr feedback fixes
Mar 17, 2022
13d7b5e
disable swiftlint body length rule
Mar 17, 2022
41590bf
supress TooManyFunctions
Mar 17, 2022
6a764a0
fix supress annotation
Mar 17, 2022
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# Changelog

## Unreleased
# Unreleased
denrase marked this conversation as resolved.
Show resolved Hide resolved

* Feat: Mobile Vitals - Native App Start (#749)
* Feat: Mobile Vitals - Native Frames (#772)

## 6.4.0-beta.3

* Feat: Allow to set startTimestamp & endTimestamp manually to SentrySpan (#676)
* Bump: Sentry-Cocoa to 7.10.0 (#777)
* Feat: Mobile Vitals - Native App Start (#749)
marandaneto marked this conversation as resolved.
Show resolved Hide resolved
* Feat: Additional Dart/Flutter context information (#778)
* Bump: Kotlin plugin to 1.5.31 (#763)
* Fix: Missing userId on iOS when userId is not set (#782)
Expand Down
7 changes: 7 additions & 0 deletions dart/lib/src/hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import 'tracing.dart';
/// Configures the scope through the callback.
typedef ScopeCallback = void Function(Scope);

/// Called when a transaction is finished.
typedef OnTransactionFinish = FutureOr<void> Function(ISentrySpan transaction);

/// SDK API contract which combines a client and scope management
class Hub {
static SentryClient _getClient(SentryOptions options) {
Expand Down Expand Up @@ -347,6 +350,7 @@ class Hub {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
Map<String, dynamic>? customSamplingContext,
}) =>
startTransactionWithContext(
Expand All @@ -360,6 +364,7 @@ class Hub {
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
trimEnd: trimEnd,
onFinish: onFinish,
customSamplingContext: customSamplingContext,
);

Expand All @@ -372,6 +377,7 @@ class Hub {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
}) {
if (!_isEnabled) {
_options.logger(
Expand Down Expand Up @@ -402,6 +408,7 @@ class Hub {
waitForChildren: waitForChildren ?? false,
autoFinishAfter: autoFinishAfter,
trimEnd: trimEnd ?? false,
onFinish: onFinish,
);
if (bindToScope ?? false) {
item.scope.span = tracer;
Expand Down
3 changes: 3 additions & 0 deletions dart/lib/src/hub_adapter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class HubAdapter implements Hub {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
}) =>
Sentry.startTransactionWithContext(
transactionContext,
Expand All @@ -134,6 +135,7 @@ class HubAdapter implements Hub {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
Map<String, dynamic>? customSamplingContext,
}) =>
Sentry.startTransaction(
Expand All @@ -145,6 +147,7 @@ class HubAdapter implements Hub {
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
trimEnd: trimEnd,
onFinish: onFinish,
customSamplingContext: customSamplingContext,
);

Expand Down
2 changes: 2 additions & 0 deletions dart/lib/src/noop_hub.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class NoOpHub implements Hub {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
Map<String, dynamic>? customSamplingContext,
}) =>
NoOpSentrySpan();
Expand All @@ -105,6 +106,7 @@ class NoOpHub implements Hub {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
}) =>
NoOpSentrySpan();

Expand Down
11 changes: 5 additions & 6 deletions dart/lib/src/protocol/sentry_transaction.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class SentryTransaction extends SentryEvent {
static const String _type = 'transaction';
late final List<SentrySpan> spans;
final SentryTracer _tracer;
late final List<SentryMeasurement>? measurements;
late final List<SentryMeasurement> measurements;

SentryTransaction(
this._tracer, {
Expand Down Expand Up @@ -56,7 +56,7 @@ class SentryTransaction extends SentryEvent {

final spanContext = _tracer.context;
spans = _tracer.children;
this.measurements = measurements;
this.measurements = measurements ?? [];

this.contexts.trace = spanContext.toTraceContext(
sampled: _tracer.sampled,
Expand All @@ -74,11 +74,10 @@ class SentryTransaction extends SentryEvent {
json['start_timestamp'] =
formatDateAsIso8601WithMillisPrecision(startTimestamp);

final ms = measurements;
if (ms != null && ms.isNotEmpty) {
if (measurements.isNotEmpty) {
final map = <String, dynamic>{};
for (final m in ms) {
map[m.name] = m.toJson();
for (final measurement in measurements) {
map[measurement.name] = measurement.toJson();
}
json['measurements'] = map;
}
Expand Down
4 changes: 4 additions & 0 deletions dart/lib/src/sentry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ class Sentry {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
Map<String, dynamic>? customSamplingContext,
}) =>
_hub.startTransaction(
Expand All @@ -240,6 +241,7 @@ class Sentry {
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
trimEnd: trimEnd,
onFinish: onFinish,
customSamplingContext: customSamplingContext,
);

Expand All @@ -252,6 +254,7 @@ class Sentry {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
}) =>
_hub.startTransactionWithContext(
transactionContext,
Expand All @@ -261,6 +264,7 @@ class Sentry {
waitForChildren: waitForChildren,
autoFinishAfter: autoFinishAfter,
trimEnd: trimEnd,
onFinish: onFinish,
);

/// Gets the current active transaction or span.
Expand Down
12 changes: 12 additions & 0 deletions dart/lib/src/sentry_measurement.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
class SentryMeasurement {
SentryMeasurement(this.name, this.value);

/// Amount of frames drawn during a transaction
SentryMeasurement.totalFrames(this.value) : name = 'frames_total';

/// Amount of slow frames drawn during a transaction.
/// A slow frame is any frame longer than 1s / refreshrate.
/// So for example any frame slower than 16ms for a refresh rate of 60hz.
SentryMeasurement.slowFrames(this.value) : name = 'frames_slow';

/// Amount of frozen frames drawn during a transaction.
/// Typically defined as frames slower than 500ms.
SentryMeasurement.frozenFrames(this.value) : name = 'frames_frozen';

SentryMeasurement.coldAppStart(Duration duration)
: assert(!duration.isNegative),
name = 'app_start_cold',
Expand Down
23 changes: 18 additions & 5 deletions dart/lib/src/sentry_tracer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ class SentryTracer extends ISentrySpan {
late final SentrySpan _rootSpan;
final List<SentrySpan> _children = [];
final Map<String, dynamic> _extra = {};
final List<SentryMeasurement> _measurements = [];

Timer? _autoFinishAfterTimer;
Function(SentryTracer)? _onFinish;
var _finishStatus = SentryTracerFinishStatus.notFinishing();
late final bool _trimEnd;

Expand All @@ -33,11 +35,15 @@ class SentryTracer extends ISentrySpan {
/// [SentryNavigatorObserver] idle transactions, where we finish the
/// transaction after a given "idle time" and we don't want this "idle time"
/// to be part of the transaction.
SentryTracer(SentryTransactionContext transactionContext, this._hub,
{DateTime? startTimestamp,
bool waitForChildren = false,
Duration? autoFinishAfter,
bool trimEnd = false}) {
SentryTracer(
SentryTransactionContext transactionContext,
this._hub, {
DateTime? startTimestamp,
bool waitForChildren = false,
Duration? autoFinishAfter,
bool trimEnd = false,
Function(SentryTracer)? onFinish,
}) {
_rootSpan = SentrySpan(
this,
transactionContext,
Expand All @@ -53,6 +59,7 @@ class SentryTracer extends ISentrySpan {
}
name = transactionContext.name;
_trimEnd = trimEnd;
_onFinish = onFinish;
}

@override
Expand Down Expand Up @@ -92,6 +99,7 @@ class SentryTracer extends ISentrySpan {
}

await _rootSpan.finish(endTimestamp: _rootEndTimestamp);
await _onFinish?.call(this);

// remove from scope
_hub.configureScope((scope) {
Expand All @@ -101,6 +109,7 @@ class SentryTracer extends ISentrySpan {
});

final transaction = SentryTransaction(this);
transaction.measurements.addAll(_measurements);
await _hub.captureTransaction(transaction);
}
}
Expand Down Expand Up @@ -240,6 +249,10 @@ class SentryTracer extends ISentrySpan {
@override
SentryTraceHeader toSentryTrace() => _rootSpan.toSentryTrace();

void addMeasurements(List<SentryMeasurement> measurements) {
_measurements.addAll(measurements);
}

bool _haveAllChildrenFinished() {
for (final child in children) {
if (!child.finished) {
Expand Down
1 change: 1 addition & 0 deletions dart/test/default_integrations_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ class PrintRecursionMockHub extends MockHub {
bool? waitForChildren,
Duration? autoFinishAfter,
bool? trimEnd,
OnTransactionFinish? onFinish,
}) {
return NoOpSentrySpan();
}
Expand Down
2 changes: 1 addition & 1 deletion flutter/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ android {
}

dependencies {
api 'io.sentry:sentry-android:5.6.1'
api 'io.sentry:sentry-android:5.6.3'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
Loading