Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
240 changes: 16 additions & 224 deletions docs/platforms/android/integrations/jetpack-compose/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ title: Jetpack Compose
caseStyle: camelCase
supportLevel: production
sdk: sentry.java.compose
description: Learn more about the Sentry Compose integration.
description: Learn more about Sentry's integrations for Jetpack Compose.
categories:
- mobile
og_image: /og-images/platforms-android-integrations-jetpack-compose.png
---

The `sentry-compose-android` library provides [Jetpack Compose](https://developer.android.com/jetpack/androidx/releases/compose) support in the following areas:
The `sentry-compose-android` and `sentry-android-navigation3` libraries provide [Jetpack Compose](https://developer.android.com/compose) support in the following areas:

- `@Composable` performance metrics
- Transaction and breadcrumb support for user interactions (clicks, swipes and scroll gestures)
- Transaction and breadcrumb support for navigation events
- Support for <PlatformLink to="/enriching-events/viewhierarchy/">View Hierarchies</PlatformLink>
- Support for user interactions (clicks, swipes and scroll gestures)
- Support for <PlatformLink to="/configuration/integrations/navigation/">navigation</PlatformLink>
- Support for <PlatformLink to="/enriching-events/viewhierarchy/">debugging view hierarchies</PlatformLink>

## Performance Metrics

Expand All @@ -28,8 +28,12 @@ With Jetpack Compose performance metrics the Sentry Android SDK can automaticall

This feature requires an underlying transaction to attach it's spans to. Transactions can be created manually or automatically by configuring

- <PlatformLink to="/tracing/instrumentation/automatic-instrumentation/">Activity instrumentation</PlatformLink>
- [Navigation Instrumentation](#jetpack-compose-navigation)
- <PlatformLink to="/tracing/instrumentation/automatic-instrumentation/">
Activity instrumentation
</PlatformLink>
- <PlatformLink to="/configuration/integrations/navigation/">
Navigation instrumentation
</PlatformLink>
- [User Interactions](#user-interactions)

</Alert>
Expand Down Expand Up @@ -132,231 +136,19 @@ fun LoginScreen() {
}
```

<Alert>

If a `@Composable` doesn't have a `.sentryTag` or a `.testTag` modifier applied, both breadcrumbs and transactions won't be captured because they can't be uniquely identified.
To automatically generate tags, refer to the docs about our <PlatformLink to="/enhance-errors/kotlin-compiler-plugin/">Sentry Kotlin Compiler Plugin</PlatformLink>.

</Alert>

<Alert>

If you want to customize the recorded breadcrumbs/transactions, you can skip to [the section below](#customize-the-recorded-breadcrumbtransaction).

</Alert>

## Jetpack Compose Navigation
#### Customize the Recorded Breadcrumb/Transaction

In this section, we get you up and running with Sentry's Compose Navigation Integration, so that it will automatically add a breadcrumb and start a transaction for each navigation event.
User interaction instrumentation uses the `sentryTag` or `testTag` value to identify the composable in the recorded breadcrumb and transaction. Keep these tags stable and free of PII or other sensitive data.

![Jetpack Compose Navigation Breadcrumbs](./img/jetpack-compose-navigation.png)

### Auto-Installation With the Sentry Android Gradle Plugin

#### Install

If you're using the [Sentry Android Gradle Plugin](/platforms/android/configuration/gradle/), the Jetpack Compose Navigation Integration is automatically applied, and both breadcrumbs and transactions are automatically created for every navigation event.

Add the Sentry Android Gradle plugin in `build.gradle`:

```groovy
plugins {
id "io.sentry.android.gradle" version "{{@inject packages.version('sentry.java.android.gradle-plugin', '3.0.0') }}"
}
```

```kotlin
plugins {
id("io.sentry.android.gradle") version "{{@inject packages.version('sentry.java.android.gradle-plugin', '3.0.0') }}"
}
```
If needed, you can filter sensitive data from breadcrumbs and transactions before they're sent to Sentry via the `SentryOptions.BeforeBreadcrumbCallback` and `SentryOptions.BeforeSendTransactionCallback`, respectively.

<Alert>

Learn more about the Sentry Android Gradle plugin in our [Gradle](/platforms/android/configuration/gradle/) documentation. Details about auto-installation can be found in the [Auto Instrumentation](/platforms/android/configuration/gradle/#tracing-auto-instrumentation) section.
If a `@Composable` doesn't have a `.sentryTag` or a `.testTag` modifier applied, both breadcrumbs and transactions won't be captured because they can't be uniquely identified.
To automatically generate tags, refer to the docs about our <PlatformLink to="/enhance-errors/kotlin-compiler-plugin/">Sentry Kotlin Compiler Plugin</PlatformLink>.

</Alert>

#### Disable

If you want to disable the Jetpack Compose instrumentation feature, you can adapt your `build.gradle(.kts)` file like so:

```groovy
import io.sentry.android.gradle.extensions.InstrumentationFeature

sentry {
tracingInstrumentation {
enabled = true
features = EnumSet.allOf(InstrumentationFeature) - InstrumentationFeature.COMPOSE
}
}
```

```kotlin
import java.util.EnumSet
import io.sentry.android.gradle.extensions.InstrumentationFeature

sentry {
tracingInstrumentation {
enabled.set(true)
features.set(EnumSet.allOf(InstrumentationFeature::class.java) - InstrumentationFeature.COMPOSE)
}
}
```

### Manual Installation

#### Install

Sentry captures data by adding a `withSentryObservableEffect` extension function to `NavHostController`. To add the Navigation integration, install the [Android SDK](/platforms/android/), then add the `sentry-compose` dependency using Gradle:

```groovy
implementation 'io.sentry:sentry-android:{{@inject packages.version('sentry.java.android', '6.2.0') }}'
implementation 'io.sentry:sentry-compose-android:{{@inject packages.version('sentry.java.compose.android', '6.2.0') }}'
```

#### Configure

Configuration should happen in the respective `@Composable` function, once you obtain an instance of `NavHostController`:

```kotlin
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import io.sentry.compose.withSentryObservableEffect

val navController = rememberNavController().withSentryObservableEffect(
enableNavigationBreadcrumbs = true, // enabled by default
enableNavigationTracing = true // enabled by default
)
NavHost(
navController = navController
) {
...
}
```

By default, the navigation transaction finishes automatically after it reaches the specified [idleTimeout](/platforms/android/configuration/options/#idleTimeout) and all of its child spans are finished. You can customize the timeout to your needs.

### Verify

This snippet includes a sample `Activity` with a couple of navigation events between composables and captures an intentional message, so you can test that everything is working as soon as you set it up:

```kotlin
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import io.sentry.Sentry
import io.sentry.compose.withSentryObservableEffect

class ComposeActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
val navController = rememberNavController().withSentryObservableEffect()
SampleNavigation(navController)
}
}
}

@Composable
fun SampleNavigation(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = "first"
) {
composable("first") {
First(
navigateToSecond = { navController.navigate("second") }
)
}
composable("second") {
Second()
}
}
}

@Composable
fun First(
navigateToSecond: () -> Unit
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Button(
onClick = { navigateToSecond() },
modifier = Modifier.padding(top = 32.dp)
) {
Text("Navigate to Second")
}
Button(
onClick = { Sentry.captureMessage("Some message from Compose.") },
modifier = Modifier.padding(top = 32.dp)
) {
Text("Message from Compose")
}
}
}

@Composable
fun Second() {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text("Second Screen")
}
}
```

## Customize the Recorded Breadcrumb/Transaction

By default, the Navigation integration captures route arguments as additional data on breadcrumbs and transactions. In case the arguments contain any PII data, you can strip it out by way of `BeforeBreadcrumbCallback` and `EventProcessor` respectively. To do that, [manually initialize](/platforms/android/manual-setup/#configuration-via-sentryoptions) the SDK and add the following snippet:

```kotlin
import io.sentry.EventProcessor
import io.sentry.android.core.SentryAndroid
import io.sentry.SentryOptions.BeforeBreadcrumbCallback
import io.sentry.android.navigation.SentryNavigationListener

SentryAndroid.init(this) { options ->
options.beforeBreadcrumb = BeforeBreadcrumbCallback { breadcrumb, hint ->
if (SentryNavigationListener.NAVIGATION_OP == breadcrumb.category) {
breadcrumb.data.remove("from_arguments")
breadcrumb.data.remove("to_arguments")
}
breadcrumb
}
options.addEventProcessor(object : EventProcessor {
override fun process(transaction: SentryTransaction, hint: Hint): SentryTransaction? {
if (SentryNavigationListener.NAVIGATION_OP == transaction.contexts.trace.operation) {
transaction.removeExtra("arguments")
}
return transaction
}
})
}
```

## Custom Telemetry in Compose

Composable functions can run many times during recomposition. Don't send custom Sentry spans, messages,
Expand Down
Loading
Loading