Skip to content

feat(android): Add Jetpack Compose automatic UI transaction docs #5893

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

Merged
merged 11 commits into from
Dec 19, 2022
Merged
Changes from 4 commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -226,24 +226,56 @@ For more information see our [file I/O integration](/platforms/android/configura

### User Interaction Instrumentation

The UI instrumentation, once enabled, captures transactions for a set of different user interactions, which include clicks, scrolls and swipes. User interaction instrumentation is available for both classic Android Views as well as Jetpack Compose UI.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The UI instrumentation, once enabled, captures transactions for a set of different user interactions, which include clicks, scrolls and swipes. User interaction instrumentation is available for both classic Android Views as well as Jetpack Compose UI.
The UI instrumentation, once enabled, captures transactions for a set of different user interactions, which include clicks, scrolls and swipes. User interaction instrumentation is available for both classic Android Views as well as the Jetpack Compose UI.


This feature is disabled by default, but you can enable it by setting:

```xml {filename:AndroidManifest.xml}
<application>
<meta-data android:name="io.sentry.traces.user-interaction.enable" android:value="true" />
</application>
```

#### User Interaction Instrumentation for Classic Android View System
_(New in version 6.0.0)_

The UI instrumentation, once enabled, captures transactions for a set of different user interactions, which include clicks, scrolls and swipes. The SDK composes the transaction name out of the host `Activity` and the `id` of the view, which captured the user interaction; for example, `LoginActivity.login_button`. The transaction operation is set to `ui.action` plus the interaction type (one of `click`, `scroll` or `swipe`).
The SDK composes the transaction name out of the host `Activity` and the `id` of the view, which captured the user interaction; for example, `LoginActivity.login_button`. The transaction operation is set to `ui.action` plus the interaction type (one of `click`, `scroll` or `swipe`).

<Note>

If the view doesn't have the `id` assigned, the transaction won't be captured because it can't be uniquely identified otherwise.

</Note>

The UI instrumentation is disabled by default, but you can enable it by setting:
#### User Interaction Instrumentation for Jetpack Compose
_(New in version 6.10.0)_

```xml {filename:AndroidManifest.xml}
<application>
<meta-data android:name="io.sentry.traces.user-interaction.enable" android:value="true" />
</application>
The SDK composes the transaction name out of the host `Activity` and the `tag` set by way of `Modifier.testTag("<tag>")` of the Composable (for example, `LoginActivity.login_button`). The transaction operation is set to `ui.action` plus the interaction type (one of `click`, `scroll`, or `swipe`).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the testTag for monitoring in production seems a bit awkward to me. Maybe we should define our own Modifier?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! @romtsn and I discussed about this as well..testTag() is used for writing Jetpack Compose UI tests to identify an element within the view hierarchy. So the use case is quite similar to ours.
I see two advantages:

  • it will work out of the box for any existing Composables
  • there's no need for an extra API
  • If we would introduce our own modifier, the users would probably end up setting the same value there as well:
Button(
    modifier = Modifier
      .testTag("button_login")
      .sentryTag("button_login") {
    ...
}

But yeah I see your point, it still could be confusing. Maybe let's wait for some user feedback and add our own API if necessary?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep - our ultimate goal would also be to automatically generate the transaction name through SAGP (either bytecode manipulation or kotlin compiler plugin), so long-term users will only need this as a fallback in rare cases, so I think it's a good middle-ground

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using testTag as a fallback if sentryTag is not set? So if you are already using testTag you are fine, because you don't have to set it twice. If you use both, sentryTag wins. Finally, we recommend using sentryTag. I'm also fine with not adding sentryTag in the first iteration. It's always easier to add APIs than to remove them.


```kotlin
import androidx.compose.ui.platform.testTag

@Composable
fun LoginScreen() {
Column {
// ...
Button(
modifier = Modifier.testTag("button_login"),
onClick = { TODO() }) {
Text(text = "Login")
}
}
}
```

<Note>

If the `@Composable` doesn't have a `testTag` modifier applied, the transaction won't be captured because it can't be uniquely identified otherwise.

</Note>

#### Transaction Lifetime

The transaction finishes automatically after it reaches the specified [idleTimeout](/platforms/android/configuration/options/#idle-timeout) and all of its child spans are finished. The `idleTimeoout` defaults to `3000` milliseconds (three seconds). You can also disable the idle timeout by setting it to `null`, but the transaction must be finished manually in this case.

<Note>
Expand Down