Skip to content

Commit 8ccdc9b

Browse files
Extract Activity Breadcrumbs generation into own Integration (#3064)
Co-authored-by: Sentry Github Bot <[email protected]>
1 parent 8ff8fd0 commit 8ccdc9b

File tree

9 files changed

+312
-205
lines changed

9 files changed

+312
-205
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Uses Process.startUptimeMillis to calculate app-start timings
1616
- To enable this feature set `options.isEnablePerformanceV2 = true`
1717
- Move slow+frozen frame calculation, as well as frame delay inside SentryFrameMetricsCollector ([#3100](https://github.com/getsentry/sentry-java/pull/3100))
18+
- Extract Activity Breadcrumbs generation into own Integration ([#3064](https://github.com/getsentry/sentry-java/pull/3064))
1819

1920
### Fixes
2021

sentry-android-core/api/sentry-android-core.api

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
public final class io/sentry/android/core/ActivityBreadcrumbsIntegration : android/app/Application$ActivityLifecycleCallbacks, io/sentry/Integration, java/io/Closeable {
2+
public fun <init> (Landroid/app/Application;)V
3+
public fun close ()V
4+
public fun onActivityCreated (Landroid/app/Activity;Landroid/os/Bundle;)V
5+
public fun onActivityDestroyed (Landroid/app/Activity;)V
6+
public fun onActivityPaused (Landroid/app/Activity;)V
7+
public fun onActivityResumed (Landroid/app/Activity;)V
8+
public fun onActivitySaveInstanceState (Landroid/app/Activity;Landroid/os/Bundle;)V
9+
public fun onActivityStarted (Landroid/app/Activity;)V
10+
public fun onActivityStopped (Landroid/app/Activity;)V
11+
public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V
12+
}
13+
114
public final class io/sentry/android/core/ActivityFramesTracker {
215
public fun <init> (Lio/sentry/android/core/LoadClass;Lio/sentry/android/core/SentryAndroidOptions;)V
316
public fun <init> (Lio/sentry/android/core/LoadClass;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/android/core/MainLooperHandler;)V
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package io.sentry.android.core;
2+
3+
import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY;
4+
import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;
5+
6+
import android.app.Activity;
7+
import android.app.Application;
8+
import android.os.Bundle;
9+
import io.sentry.Breadcrumb;
10+
import io.sentry.Hint;
11+
import io.sentry.IHub;
12+
import io.sentry.Integration;
13+
import io.sentry.SentryLevel;
14+
import io.sentry.SentryOptions;
15+
import io.sentry.util.Objects;
16+
import java.io.Closeable;
17+
import java.io.IOException;
18+
import org.jetbrains.annotations.NotNull;
19+
import org.jetbrains.annotations.Nullable;
20+
21+
/** Automatically adds breadcrumbs for Activity Lifecycle Events. */
22+
public final class ActivityBreadcrumbsIntegration
23+
implements Integration, Closeable, Application.ActivityLifecycleCallbacks {
24+
25+
private final @NotNull Application application;
26+
private @Nullable IHub hub;
27+
private boolean enabled;
28+
29+
public ActivityBreadcrumbsIntegration(final @NotNull Application application) {
30+
this.application = Objects.requireNonNull(application, "Application is required");
31+
}
32+
33+
@Override
34+
public void register(final @NotNull IHub hub, final @NotNull SentryOptions options) {
35+
final SentryAndroidOptions androidOptions =
36+
Objects.requireNonNull(
37+
(options instanceof SentryAndroidOptions) ? (SentryAndroidOptions) options : null,
38+
"SentryAndroidOptions is required");
39+
40+
this.hub = Objects.requireNonNull(hub, "Hub is required");
41+
this.enabled = androidOptions.isEnableActivityLifecycleBreadcrumbs();
42+
options
43+
.getLogger()
44+
.log(SentryLevel.DEBUG, "ActivityBreadcrumbsIntegration enabled: %s", enabled);
45+
46+
if (enabled) {
47+
application.registerActivityLifecycleCallbacks(this);
48+
options.getLogger().log(SentryLevel.DEBUG, "ActivityBreadcrumbIntegration installed.");
49+
addIntegrationToSdkVersion(getClass());
50+
}
51+
}
52+
53+
@Override
54+
public void close() throws IOException {
55+
if (enabled) {
56+
application.unregisterActivityLifecycleCallbacks(this);
57+
if (hub != null) {
58+
hub.getOptions()
59+
.getLogger()
60+
.log(SentryLevel.DEBUG, "ActivityBreadcrumbsIntegration removed.");
61+
}
62+
}
63+
}
64+
65+
@Override
66+
public synchronized void onActivityCreated(
67+
final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) {
68+
addBreadcrumb(activity, "created");
69+
}
70+
71+
@Override
72+
public synchronized void onActivityStarted(final @NotNull Activity activity) {
73+
addBreadcrumb(activity, "started");
74+
}
75+
76+
@Override
77+
public synchronized void onActivityResumed(final @NotNull Activity activity) {
78+
addBreadcrumb(activity, "resumed");
79+
}
80+
81+
@Override
82+
public synchronized void onActivityPaused(final @NotNull Activity activity) {
83+
addBreadcrumb(activity, "paused");
84+
}
85+
86+
@Override
87+
public synchronized void onActivityStopped(final @NotNull Activity activity) {
88+
addBreadcrumb(activity, "stopped");
89+
}
90+
91+
@Override
92+
public synchronized void onActivitySaveInstanceState(
93+
final @NotNull Activity activity, final @NotNull Bundle outState) {
94+
addBreadcrumb(activity, "saveInstanceState");
95+
}
96+
97+
@Override
98+
public synchronized void onActivityDestroyed(final @NotNull Activity activity) {
99+
addBreadcrumb(activity, "destroyed");
100+
}
101+
102+
private void addBreadcrumb(final @NotNull Activity activity, final @NotNull String state) {
103+
if (hub == null) {
104+
return;
105+
}
106+
107+
final Breadcrumb breadcrumb = new Breadcrumb();
108+
breadcrumb.setType("navigation");
109+
breadcrumb.setData("state", state);
110+
breadcrumb.setData("screen", getActivityName(activity));
111+
breadcrumb.setCategory("ui.lifecycle");
112+
breadcrumb.setLevel(SentryLevel.INFO);
113+
114+
final Hint hint = new Hint();
115+
hint.set(ANDROID_ACTIVITY, activity);
116+
117+
hub.addBreadcrumb(breadcrumb, hint);
118+
}
119+
120+
private @NotNull String getActivityName(final @NotNull Activity activity) {
121+
return activity.getClass().getSimpleName();
122+
}
123+
}

sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package io.sentry.android.core;
22

33
import static io.sentry.MeasurementUnit.Duration.MILLISECOND;
4-
import static io.sentry.TypeCheckHint.ANDROID_ACTIVITY;
54
import static io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion;
65

76
import android.app.Activity;
@@ -12,9 +11,7 @@
1211
import android.os.Looper;
1312
import android.view.View;
1413
import androidx.annotation.NonNull;
15-
import io.sentry.Breadcrumb;
1614
import io.sentry.FullyDisplayedReporter;
17-
import io.sentry.Hint;
1815
import io.sentry.IHub;
1916
import io.sentry.IScope;
2017
import io.sentry.ISpan;
@@ -112,13 +109,6 @@ public void register(final @NotNull IHub hub, final @NotNull SentryOptions optio
112109

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

115-
this.options
116-
.getLogger()
117-
.log(
118-
SentryLevel.DEBUG,
119-
"ActivityLifecycleIntegration enabled: %s",
120-
this.options.isEnableActivityLifecycleBreadcrumbs());
121-
122112
performanceEnabled = isPerformanceEnabled(this.options);
123113
fullyDisplayedReporter = this.options.getFullyDisplayedReporter();
124114
timeToFullDisplaySpanEnabled = this.options.isEnableTimeToFullDisplayTracing();
@@ -143,22 +133,6 @@ public void close() throws IOException {
143133
activityFramesTracker.stop();
144134
}
145135

146-
private void addBreadcrumb(final @NotNull Activity activity, final @NotNull String state) {
147-
if (options != null && hub != null && options.isEnableActivityLifecycleBreadcrumbs()) {
148-
final Breadcrumb breadcrumb = new Breadcrumb();
149-
breadcrumb.setType("navigation");
150-
breadcrumb.setData("state", state);
151-
breadcrumb.setData("screen", getActivityName(activity));
152-
breadcrumb.setCategory("ui.lifecycle");
153-
breadcrumb.setLevel(SentryLevel.INFO);
154-
155-
final Hint hint = new Hint();
156-
hint.set(ANDROID_ACTIVITY, activity);
157-
158-
hub.addBreadcrumb(breadcrumb, hint);
159-
}
160-
}
161-
162136
private @NotNull String getActivityName(final @NotNull Activity activity) {
163137
return activity.getClass().getSimpleName();
164138
}
@@ -385,7 +359,6 @@ private void finishTransaction(
385359
public synchronized void onActivityCreated(
386360
final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) {
387361
setColdStart(savedInstanceState);
388-
addBreadcrumb(activity, "created");
389362
if (hub != null) {
390363
final @Nullable String activityClassName = ClassUtil.getClassName(activity);
391364
hub.configureScope(scope -> scope.setScreen(activityClassName));
@@ -411,7 +384,6 @@ public synchronized void onActivityStarted(final @NotNull Activity activity) {
411384
// working. Moving this to onActivityStarted fixes the problem.
412385
activityFramesTracker.addActivity(activity);
413386
}
414-
addBreadcrumb(activity, "started");
415387
}
416388

417389
@Override
@@ -430,7 +402,6 @@ public synchronized void onActivityResumed(final @NotNull Activity activity) {
430402
mainHandler.post(() -> onFirstFrameDrawn(ttfdSpan, ttidSpan));
431403
}
432404
}
433-
addBreadcrumb(activity, "resumed");
434405
}
435406

436407
@Override
@@ -460,24 +431,22 @@ public synchronized void onActivityPaused(final @NotNull Activity activity) {
460431
lastPausedTime = hub.getOptions().getDateProvider().now();
461432
}
462433
}
463-
addBreadcrumb(activity, "paused");
464434
}
465435

466436
@Override
467437
public synchronized void onActivityStopped(final @NotNull Activity activity) {
468-
addBreadcrumb(activity, "stopped");
438+
// no-op
469439
}
470440

471441
@Override
472442
public synchronized void onActivitySaveInstanceState(
473443
final @NotNull Activity activity, final @NotNull Bundle outState) {
474-
addBreadcrumb(activity, "saveInstanceState");
444+
// no-op
475445
}
476446

477447
@Override
478448
public synchronized void onActivityDestroyed(final @NotNull Activity activity) {
479-
if (performanceEnabled || options.isEnableActivityLifecycleBreadcrumbs()) {
480-
addBreadcrumb(activity, "destroyed");
449+
if (performanceEnabled) {
481450

482451
// in case the appStartSpan isn't completed yet, we finish it as cancelled to avoid
483452
// memory leak

sentry-android-core/src/main/java/io/sentry/android/core/AndroidOptionsInitializer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ static void installDefaultIntegrations(
244244
options.addIntegration(
245245
new ActivityLifecycleIntegration(
246246
(Application) context, buildInfoProvider, activityFramesTracker));
247+
options.addIntegration(new ActivityBreadcrumbsIntegration((Application) context));
247248
options.addIntegration(new CurrentActivityIntegration((Application) context));
248249
options.addIntegration(new UserInteractionIntegration((Application) context, loadClass));
249250
if (isFragmentAvailable) {

0 commit comments

Comments
 (0)