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: Measure app start time #1487

Merged
merged 23 commits into from
Jun 11, 2021
Merged
Changes from 1 commit
Commits
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
draft
marandaneto committed May 25, 2021
commit 7c38b2c283ce5f6491f881c81f15b302d30ceaa0
5 changes: 0 additions & 5 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
@@ -73,11 +73,6 @@ public final class io/sentry/android/core/NdkIntegration : io/sentry/Integration
public final fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
}

public final class io/sentry/android/core/PerformanceAndroidEventProcessor : io/sentry/EventProcessor {
public fun <init> ()V
public fun process (Lio/sentry/protocol/SentryTransaction;Ljava/lang/Object;)Lio/sentry/protocol/SentryTransaction;
}

public final class io/sentry/android/core/PhoneStateBreadcrumbsIntegration : io/sentry/Integration, java/io/Closeable {
public fun <init> (Landroid/content/Context;)V
public fun close ()V
Original file line number Diff line number Diff line change
@@ -34,7 +34,9 @@ public final class ActivityLifecycleIntegration

private boolean isAllActivityCallbacksAvailable;

/** if the very first Activity has been already created */
private boolean firstActivityCreated = false;
/** if the very first Activity has been already resumed */
private boolean firstActivityResumed = false;

// WeakHashMap isn't thread safe but ActivityLifecycleCallbacks is only called from the
@@ -189,7 +191,8 @@ public synchronized void onActivityPreCreated(
@Override
public synchronized void onActivityCreated(
final @NonNull Activity activity, final @Nullable Bundle savedInstanceState) {
if (!firstActivityCreated) {
if (!firstActivityCreated && performanceEnabled) {
// if Activity has savedInstanceState then its a warm start
AppStartState.getInstance().setColdStart(savedInstanceState == null);
firstActivityCreated = true;
}
@@ -209,7 +212,8 @@ public synchronized void onActivityStarted(final @NonNull Activity activity) {

@Override
public synchronized void onActivityResumed(final @NonNull Activity activity) {
if (!firstActivityResumed) {
if (!firstActivityResumed && performanceEnabled) {
// sets App start as finished when the very first activity calls onResume
AppStartState.getInstance().setAppStartEnd();
firstActivityResumed = true;
}
Original file line number Diff line number Diff line change
@@ -105,7 +105,7 @@ static void init(
readDefaultOptionValues(options, context);

options.addEventProcessor(new DefaultAndroidEventProcessor(context, logger, buildInfoProvider));
options.addEventProcessor(new PerformanceAndroidEventProcessor());
options.addEventProcessor(new PerformanceAndroidEventProcessor(options));

options.setTransportGate(new AndroidTransportGate(context, options.getLogger()));
}
Original file line number Diff line number Diff line change
@@ -5,13 +5,24 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/** AppStartState holds the state of the App Start metric and appStartTime */
final class AppStartState {

private static final @NotNull AppStartState instance = new AppStartState();

/** appStart in milliseconds */
private @Nullable Long appStart;

/** appStartEnd in milliseconds */
private @Nullable Long appStartEnd;

/**
* The type of App start coldStart=true -> Cold start coldStart=false -> Warm start coldStart=null
* -> unknown yet
*/
private @Nullable Boolean coldStart;

/** appStart as a Date used in the App's Context */
private @Nullable Date appStartTime;

private AppStartState() {}
Original file line number Diff line number Diff line change
@@ -6,7 +6,14 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class PerformanceAndroidEventProcessor implements EventProcessor {
/** Event Processor responsable for adding Android metrics to transactions */
final class PerformanceAndroidEventProcessor implements EventProcessor {

final @NotNull SentryAndroidOptions options;

PerformanceAndroidEventProcessor(final @NotNull SentryAndroidOptions options) {
this.options = options;
}

// transactions may be started in parallel, making this field volatile instead of a lock
// to avoid contention.
@@ -17,8 +24,9 @@ public final class PerformanceAndroidEventProcessor implements EventProcessor {
@NotNull SentryTransaction transaction, @Nullable Object hint) {
// the app start metric is sent only once when the 1st transaction happens
// after the app start is collected.
if (!sentStartMeasurement) {
if (!sentStartMeasurement && options.isTracingEnabled()) {
Long appStartUpInterval = AppStartState.getInstance().getAppStartInterval();
// if appStartUpInterval is null, metrics are not ready to be sent
if (appStartUpInterval != null) {
MeasurementValue value = new MeasurementValue((float) appStartUpInterval);

Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@
/** Sentry initialization class */
public final class SentryAndroid {

// static to rely on Class load
// static to rely on Class load init.
private static final @NotNull Date appStartTime = DateUtils.getCurrentDateTime();
// SystemClock.uptimeMillis() isn't affected by phone provider or clock changes.
private static final long appStart = SystemClock.uptimeMillis();

private SentryAndroid() {}