Skip to content

Commit

Permalink
Merge 59f2b2d into b8a1b57
Browse files Browse the repository at this point in the history
  • Loading branch information
markushi authored Dec 12, 2023
2 parents b8a1b57 + 59f2b2d commit 2c5c35b
Show file tree
Hide file tree
Showing 9 changed files with 312 additions and 205 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Support multiple debug-metadata.properties ([#3024](https://github.com/getsentry/sentry-java/pull/3024))
- (Internal, Experimental) Attach spans for Application, ContentProvider, and Activities to app-start ([#3057](https://github.com/getsentry/sentry-java/pull/3057))
- (Internal) Extract Activity Breadcrumbs generation into own Integration ([#3064](https://github.com/getsentry/sentry-java/pull/3064))

### Fixes

Expand Down
13 changes: 13 additions & 0 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
public final class io/sentry/android/core/ActivityBreadcrumbsIntegration : android/app/Application$ActivityLifecycleCallbacks, io/sentry/Integration, java/io/Closeable {
public fun <init> (Landroid/app/Application;)V
public fun close ()V
public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V
public fun onActivityDestroyed (Landroid/app/Activity;)V
public fun onActivityPaused (Landroid/app/Activity;)V
public fun onActivityResumed (Landroid/app/Activity;)V
public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V
public fun onActivityStarted (Landroid/app/Activity;)V
public fun onActivityStopped (Landroid/app/Activity;)V
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
}

public final class io/sentry/android/core/ActivityFramesTracker {
public fun <init> (Lio/sentry/android/core/LoadClass;Lio/sentry/android/core/SentryAndroidOptions;)V
public fun <init> (Lio/sentry/android/core/LoadClass;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/MainLooperHandler;)V
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package io.sentry.android.core;

import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY;
import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import io.sentry.Breadcrumb;
import io.sentry.Hint;
import io.sentry.IHub;
import io.sentry.Integration;
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.util.Objects;
import java.io.Closeable;
import java.io.IOException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/** Automatically adds breadcrumbs for Activity Lifecycle Events. */
public final class ActivityBreadcrumbsIntegration
implements Integration, Closeable, Application.ActivityLifecycleCallbacks {

private final @NotNull Application application;
private @Nullable IHub hub;
private boolean enabled;

public ActivityBreadcrumbsIntegration(final @NotNull Application application) {
this.application = Objects.requireNonNull(application, "Application is required");
}

@Override
public void register(final @NotNull IHub hub, final @NotNull SentryOptions options) {
final SentryAndroidOptions androidOptions =
Objects.requireNonNull(
(options instanceof SentryAndroidOptions) ? (SentryAndroidOptions) options : null,
"SentryAndroidOptions is required");

this.hub = Objects.requireNonNull(hub, "Hub is required");
this.enabled = androidOptions.isEnableActivityLifecycleBreadcrumbs();
options
.getLogger()
.log(SentryLevel.DEBUG, "ActivityBreadcrumbsIntegration enabled: %s", enabled);

if (enabled) {
application.registerActivityLifecycleCallbacks(this);
options.getLogger().log(SentryLevel.DEBUG, "ActivityBreadcrumbIntegration installed.");
addIntegrationToSdkVersion(getClass());
}
}

@Override
public void close() throws IOException {
if (enabled) {
application.unregisterActivityLifecycleCallbacks(this);
if (hub != null) {
hub.getOptions()
.getLogger()
.log(SentryLevel.DEBUG, "ActivityBreadcrumbsIntegration removed.");
}
}
}

@Override
public synchronized void onActivityCreated(
final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) {
addBreadcrumb(activity, "created");
}

@Override
public synchronized void onActivityStarted(final @NotNull Activity activity) {
addBreadcrumb(activity, "started");
}

@Override
public synchronized void onActivityResumed(final @NotNull Activity activity) {
addBreadcrumb(activity, "resumed");
}

@Override
public synchronized void onActivityPaused(final @NotNull Activity activity) {
addBreadcrumb(activity, "paused");
}

@Override
public synchronized void onActivityStopped(final @NotNull Activity activity) {
addBreadcrumb(activity, "stopped");
}

@Override
public synchronized void onActivitySaveInstanceState(
final @NotNull Activity activity, final @NotNull Bundle outState) {
addBreadcrumb(activity, "saveInstanceState");
}

@Override
public synchronized void onActivityDestroyed(final @NotNull Activity activity) {
addBreadcrumb(activity, "destroyed");
}

private void addBreadcrumb(final @NotNull Activity activity, final @NotNull String state) {
if (hub == null) {
return;
}

final Breadcrumb breadcrumb = new Breadcrumb();
breadcrumb.setType("navigation");
breadcrumb.setData("state", state);
breadcrumb.setData("screen", getActivityName(activity));
breadcrumb.setCategory("ui.lifecycle");
breadcrumb.setLevel(SentryLevel.INFO);

final Hint hint = new Hint();
hint.set(ANDROID_ACTIVITY, activity);

hub.addBreadcrumb(breadcrumb, hint);
}

private @NotNull String getActivityName(final @NotNull Activity activity) {
return activity.getClass().getSimpleName();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.sentry.android.core;

import static io.sentry.MeasurementUnit.Duration.MILLISECOND;
import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY;
import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;

import android.app.Activity;
Expand All @@ -12,9 +11,7 @@
import android.os.Looper;
import android.view.View;
import androidx.annotation.NonNull;
import io.sentry.Breadcrumb;
import io.sentry.FullyDisplayedReporter;
import io.sentry.Hint;
import io.sentry.IHub;
import io.sentry.IScope;
import io.sentry.ISpan;
Expand Down Expand Up @@ -112,13 +109,6 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio

this.hub = Objects.requireNonNull(hub, "Hub is required");

this.options
.getLogger()
.log(
SentryLevel.DEBUG,
"ActivityLifecycleIntegration enabled: %s",
this.options.isEnableActivityLifecycleBreadcrumbs());

performanceEnabled = isPerformanceEnabled(this.options);
fullyDisplayedReporter = this.options.getFullyDisplayedReporter();
timeToFullDisplaySpanEnabled = this.options.isEnableTimeToFullDisplayTracing();
Expand All @@ -143,22 +133,6 @@ public void close() throws IOException {
activityFramesTracker.stop();
}

private void addBreadcrumb(final @NotNull Activity activity, final @NotNull String state) {
if (options != null && hub != null && options.isEnableActivityLifecycleBreadcrumbs()) {
final Breadcrumb breadcrumb = new Breadcrumb();
breadcrumb.setType("navigation");
breadcrumb.setData("state", state);
breadcrumb.setData("screen", getActivityName(activity));
breadcrumb.setCategory("ui.lifecycle");
breadcrumb.setLevel(SentryLevel.INFO);

final Hint hint = new Hint();
hint.set(ANDROID_ACTIVITY, activity);

hub.addBreadcrumb(breadcrumb, hint);
}
}

private @NotNull String getActivityName(final @NotNull Activity activity) {
return activity.getClass().getSimpleName();
}
Expand Down Expand Up @@ -385,7 +359,6 @@ private void finishTransaction(
public synchronized void onActivityCreated(
final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) {
setColdStart(savedInstanceState);
addBreadcrumb(activity, "created");
if (hub != null) {
final @Nullable String activityClassName = ClassUtil.getClassName(activity);
hub.configureScope(scope -> scope.setScreen(activityClassName));
Expand All @@ -411,7 +384,6 @@ public synchronized void onActivityStarted(final @NotNull Activity activity) {
// working. Moving this to onActivityStarted fixes the problem.
activityFramesTracker.addActivity(activity);
}
addBreadcrumb(activity, "started");
}

@Override
Expand All @@ -430,7 +402,6 @@ public synchronized void onActivityResumed(final @NotNull Activity activity) {
mainHandler.post(() -> onFirstFrameDrawn(ttfdSpan, ttidSpan));
}
}
addBreadcrumb(activity, "resumed");
}

@Override
Expand Down Expand Up @@ -460,24 +431,22 @@ public synchronized void onActivityPaused(final @NotNull Activity activity) {
lastPausedTime = hub.getOptions().getDateProvider().now();
}
}
addBreadcrumb(activity, "paused");
}

@Override
public synchronized void onActivityStopped(final @NotNull Activity activity) {
addBreadcrumb(activity, "stopped");
// no-op
}

@Override
public synchronized void onActivitySaveInstanceState(
final @NotNull Activity activity, final @NotNull Bundle outState) {
addBreadcrumb(activity, "saveInstanceState");
// no-op
}

@Override
public synchronized void onActivityDestroyed(final @NotNull Activity activity) {
if (performanceEnabled || options.isEnableActivityLifecycleBreadcrumbs()) {
addBreadcrumb(activity, "destroyed");
if (performanceEnabled) {

// in case the appStartSpan isn't completed yet, we finish it as cancelled to avoid
// memory leak
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ static void installDefaultIntegrations(
options.addIntegration(
new ActivityLifecycleIntegration(
(Application) context, buildInfoProvider, activityFramesTracker));
options.addIntegration(new ActivityBreadcrumbsIntegration((Application) context));
options.addIntegration(new CurrentActivityIntegration((Application) context));
options.addIntegration(new UserInteractionIntegration((Application) context, loadClass));
if (isFragmentAvailable) {
Expand Down
Loading

0 comments on commit 2c5c35b

Please sign in to comment.