From 401c5eafd48d450e47fc584af0911eea9c59d9c2 Mon Sep 17 00:00:00 2001 From: stefanosiano Date: Tue, 7 Jan 2025 16:14:43 +0100 Subject: [PATCH 1/4] ActivityLifecycleIntegration creates activity spans for all Activities, not only for appStart ones --- .../core/ActivityLifecycleIntegration.java | 6 ++- .../ActivityLifecycleSpanHelper.java | 19 +++++----- .../core/ActivityLifecycleIntegrationTest.kt | 37 +++++++++++++++++++ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java index 14141bf4bba..d23efc3e34f 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java @@ -417,7 +417,8 @@ public void onActivityPostCreated( final @NotNull Activity activity, final @Nullable Bundle savedInstanceState) { final ActivityLifecycleSpanHelper helper = activitySpanHelpers.get(activity); if (helper != null) { - helper.createAndStopOnCreateSpan(appStartSpan); + helper.createAndStopOnCreateSpan( + appStartSpan != null ? appStartSpan : activitiesWithOngoingTransactions.get(activity)); } } @@ -453,7 +454,8 @@ public synchronized void onActivityStarted(final @NotNull Activity activity) { public void onActivityPostStarted(final @NotNull Activity activity) { final ActivityLifecycleSpanHelper helper = activitySpanHelpers.get(activity); if (helper != null) { - helper.createAndStopOnStartSpan(appStartSpan); + helper.createAndStopOnStartSpan( + appStartSpan != null ? appStartSpan : activitiesWithOngoingTransactions.get(activity)); // Needed to handle hybrid SDKs helper.saveSpanToAppStartMetrics(); } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/performance/ActivityLifecycleSpanHelper.java b/sentry-android-core/src/main/java/io/sentry/android/core/performance/ActivityLifecycleSpanHelper.java index 7fed5e0fdbe..fead459ba88 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/performance/ActivityLifecycleSpanHelper.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/performance/ActivityLifecycleSpanHelper.java @@ -36,18 +36,18 @@ public void setOnStartStartTimestamp(final @NotNull SentryDate onStartStartTimes this.onStartStartTimestamp = onStartStartTimestamp; } - public void createAndStopOnCreateSpan(final @Nullable ISpan appStartSpan) { - if (onCreateStartTimestamp != null && appStartSpan != null) { + public void createAndStopOnCreateSpan(final @Nullable ISpan parentSpan) { + if (onCreateStartTimestamp != null && parentSpan != null) { onCreateSpan = - createLifecycleSpan(appStartSpan, activityName + ".onCreate", onCreateStartTimestamp); + createLifecycleSpan(parentSpan, activityName + ".onCreate", onCreateStartTimestamp); onCreateSpan.finish(); } } - public void createAndStopOnStartSpan(final @Nullable ISpan appStartSpan) { - if (onStartStartTimestamp != null && appStartSpan != null) { + public void createAndStopOnStartSpan(final @Nullable ISpan parentSpan) { + if (onStartStartTimestamp != null && parentSpan != null) { onStartSpan = - createLifecycleSpan(appStartSpan, activityName + ".onStart", onStartStartTimestamp); + createLifecycleSpan(parentSpan, activityName + ".onStart", onStartStartTimestamp); onStartSpan.finish(); } } @@ -106,19 +106,18 @@ public void saveSpanToAppStartMetrics() { } private @NotNull ISpan createLifecycleSpan( - final @NotNull ISpan appStartSpan, + final @NotNull ISpan parentSpan, final @NotNull String description, final @NotNull SentryDate startTimestamp) { final @NotNull ISpan span = - appStartSpan.startChild( + parentSpan.startChild( APP_METRICS_ACTIVITIES_OP, description, startTimestamp, Instrumenter.SENTRY); setDefaultStartSpanData(span); return span; } public void clear() { - // in case the appStartSpan isn't completed yet, we finish it as cancelled to avoid - // memory leak + // in case the parentSpan isn't completed yet, we finish it as cancelled to avoid memory leak if (onCreateSpan != null && !onCreateSpan.isFinished()) { onCreateSpan.finish(SpanStatus.CANCELLED); } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt index e9021c68302..5177183c900 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt @@ -1484,6 +1484,43 @@ class ActivityLifecycleIntegrationTest { assertFalse(appStartMetrics.activityLifecycleTimeSpans.isEmpty()) } + @Test + fun `Creates activity lifecycle spans even when no app start span is available`() { + val sut = fixture.getSut() + fixture.options.tracesSampleRate = 1.0 + val startDate = SentryNanotimeDate(Date(2), 0) + val appStartMetrics = AppStartMetrics.getInstance() + val activity = mock() + fixture.options.dateProvider = SentryDateProvider { startDate } + // Don't set app start time, so there's no app start span + // setAppStartTime(appStartDate) + + sut.register(fixture.hub, fixture.options) + assertTrue(sut.activitySpanHelpers.isEmpty()) + + sut.onActivityPreCreated(activity, null) + + assertFalse(sut.activitySpanHelpers.isEmpty()) + val helper = sut.activitySpanHelpers.values.first() + assertNotNull(helper.onCreateStartTimestamp) + + sut.onActivityCreated(activity, null) + assertNull(sut.appStartSpan) + + sut.onActivityPostCreated(activity, null) + assertTrue(helper.onCreateSpan!!.isFinished) + + sut.onActivityPreStarted(activity) + assertNotNull(helper.onStartStartTimestamp) + + sut.onActivityStarted(activity) + assertTrue(appStartMetrics.activityLifecycleTimeSpans.isEmpty()) + + sut.onActivityPostStarted(activity) + assertTrue(helper.onStartSpan!!.isFinished) + assertFalse(appStartMetrics.activityLifecycleTimeSpans.isEmpty()) + } + @Test fun `Save activity lifecycle spans in AppStartMetrics onPostSarted`() { val sut = fixture.getSut() From 4aecfa5b0e3c032de75675c5c5a46ea52891a62e Mon Sep 17 00:00:00 2001 From: stefanosiano Date: Tue, 7 Jan 2025 16:21:25 +0100 Subject: [PATCH 2/4] updated changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6c9c37558..3d5c3f51a77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Warm starts cleanup ([#3954](https://github.com/getsentry/sentry-java/pull/3954)) +## Behavioural Changes + +- Create onCreate and onStart spans for all Activities ([#4025](https://github.com/getsentry/sentry-java/pull/4025)) + ### Dependencies - Bump Native SDK from v0.7.16 to v0.7.17 ([#4003](https://github.com/getsentry/sentry-java/pull/4003)) From c42eb570e94ebe19703d99d7c158eba02d76d6b3 Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 6 Feb 2025 10:32:19 +0100 Subject: [PATCH 3/4] Fix test --- .../io/sentry/android/core/ActivityLifecycleIntegrationTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt index 1fb3a326cb3..a14f62c3f03 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt @@ -1572,7 +1572,7 @@ class ActivityLifecycleIntegrationTest { // Don't set app start time, so there's no app start span // setAppStartTime(appStartDate) - sut.register(fixture.hub, fixture.options) + sut.register(fixture.scopes, fixture.options) assertTrue(sut.activitySpanHelpers.isEmpty()) sut.onActivityPreCreated(activity, null) From b26179a67a866744c2f9dc8f6695deff3f82977d Mon Sep 17 00:00:00 2001 From: Roman Zavarnitsyn Date: Thu, 6 Feb 2025 10:33:28 +0100 Subject: [PATCH 4/4] Changelog --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6c380b8f31..cfd31db09c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - The Kotlin Language version is now set to 1.6 ([#3936](https://github.com/getsentry/sentry-java/pull/3936)) +### Features + +- Create onCreate and onStart spans for all Activities ([#4025](https://github.com/getsentry/sentry-java/pull/4025)) + ### Fixes - Do not log if `OtelContextScopesStorage` cannot be found ([#4127](https://github.com/getsentry/sentry-java/pull/4127)) @@ -17,10 +21,6 @@ - Fix SIGABRT native crashes on Motorola devices when encoding a video - Mention javadoc and sources for published artifacts in Gradle `.module` metadata ([#3936](https://github.com/getsentry/sentry-java/pull/3936)) -## Behavioural Changes - -- Create onCreate and onStart spans for all Activities ([#4025](https://github.com/getsentry/sentry-java/pull/4025)) - ### Dependencies - Bump Native SDK from v0.7.19 to v0.7.20 ([#4128](https://github.com/getsentry/sentry-java/pull/4128))