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

User interaction breadcrumbs not initialized when initializing Sentry after activity started #3746

Open
davidschreiber opened this issue Oct 2, 2024 · 6 comments

Comments

@davidschreiber
Copy link

Integration

sentry-android

Build System

Gradle

AGP Version

8.5.1

Proguard

Enabled

Version

7.14.0

Steps to Reproduce

  1. Disable auto-initialization by adding the appropriate metadata entry to the app's manifest:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <application>
            <meta-data android:name="io.sentry.auto-init" android:value="false" />
        </application>
    </manifest>
  2. Wait for the MainActivity to start (i.e. to receive onStart()).

  3. Initialize Sentry manually using Sentry.init(...), making sure to enable user interaction breadcrumbs:

    SentryAndroid.init(this) { options ->
      options.isDebug = true
      options.enableAllAutoBreadcrumbs(true)
      options.isEnableUserInteractionBreadcrumbs = true
    }
  4. Perform UI interactions (on tagged components). Observe that no interaction is logged to Logcat (despite debug mode and other breadcrumbs being correctly generated).

  5. Put the app into the background (causing onPause() and onStop() to be called on the activity)

  6. Bring the app back into the foreground (causing onStart() and onResume() to be called on the activity).

  7. Retry UI interactions and observe that UI interactions are correctly tracked now.

Expected Result

UI interactions should be tracked starting with the initialization of Sentry, even if it happens after the activity was first started.

Actual Result

UI interaction won't be tracked, until the first time the activity is backgrounded and foregrounded again or a workaround (like this one) is applied:

// This is a workaround for an issue coming from the delayed initialization of Sentry.
// If the activity starts before Sentry is initialized, we're missing interaction
// breadcrumbs. This will ensure that interaction breadcrumbs are still collected.
val activity = this
Didomi.getInstance().apply {
    onReady {
        if(Sentry.isEnabled()) {
            Sentry.configureScope { scope ->
                val lifecycleState = activity.lifecycle.currentState
                scope.options
                    .integrations
                    .filterIsInstance<ActivityLifecycleCallbacks>()
                    .forEach { integration ->
                        if (lifecycleState.isAtLeast(Lifecycle.State.CREATED)) {
                            integration.onActivityCreated(activity, null)
                        }
                        if (lifecycleState.isAtLeast(Lifecycle.State.STARTED)) {
                            integration.onActivityStarted(activity)
                        }
                        if (lifecycleState.isAtLeast(Lifecycle.State.RESUMED)) {
                            integration.onActivityResumed(activity)
                        }
                    }
            }
        }
    }
}
@davidschreiber
Copy link
Author

To further provide information about why this is a use case: We're only allowed to initialize Sentry after receiving the user's privacy consent, which will be asked for after the activity first started. After receiving the consent, we initialize Sentry, but won't receive any interaction breadcrumbs (if not using the workaround).

@kahest
Copy link
Member

kahest commented Oct 7, 2024

Hey @davidschreiber thanks for writing in and describing the workaround, that's helpful context. We'll look into this, and while I can't give an ETA right now, it's possible that this is a reasonably quick fix.

@romtsn
Copy link
Member

romtsn commented Oct 7, 2024

@davidschreiber I'm not sure there's a way to fix this on our side to be honest. We'd have to register for activity callbacks somewhere, but if we do so before Sentry.init, we'd violate your privacy rules in a way, because we'd already start "collecting" telemetry at that point.

In theory we could register for activity callbacks in a content provider, and then keep a ref to the last known activity to use it later for our integrations, but that content provider could as well be removed.

@davidschreiber
Copy link
Author

Do you mean that the content provider could be removed by SDK users via manifest merger removal? If the content provider's sole job is to ensure that late initialization doesn't break integrations, I guess it would be fair to assume that said functionality regresses if one removes the provider.

I understand that the use case complicates the stack, but I also assume that late initialization is not really an edge case (or at least I would hope that at least some apps treat user privacy in a way that requires deferring sending of crash reports). However, I'm concerned that the workaround we're currently using is using too much knowledge of the SDK's inner workings instead of using a well-defined public API meant for late initialization, and thus we're at risk of having the workaround break with future versions of Sentry. Even if an activity registry inside Sentry is not in scope, I would appreciate seeing some official way of late-initializing the integrations, so that they start working right from the moment Sentry was initialized.

@romtsn
Copy link
Member

romtsn commented Oct 7, 2024

Do you mean that the content provider could be removed by SDK users via manifest merger removal? If the content provider's sole job is to ensure that late initialization doesn't break integrations, I guess it would be fair to assume that said functionality regresses if one removes the provider.

right. Most likely we wouldn't introduce a new content provider, but use an existing one (SentryInitProvider), which is prone to be removed sometimes.

I would appreciate seeing some official way of late-initializing the integrations, so that they start working right from the moment Sentry was initialized.

Yeah, that's a good point, and we'll definitely discuss this! thanks for the ideas.

@markushi
Copy link
Member

markushi commented Oct 9, 2024

We could use our existing ContentProvider to populate the CurrentActivityHolder. Once SDK.init is called, we could fetch the "existing" activity from there. Downside: If ContentProvider is removed, this won't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Status: Backlog
Development

No branches or pull requests

4 participants