Skip to content

Commit

Permalink
Merge b8689b2 into fe30606
Browse files Browse the repository at this point in the history
  • Loading branch information
markushi authored Feb 9, 2023
2 parents fe30606 + b8689b2 commit 17a5b01
Show file tree
Hide file tree
Showing 20 changed files with 652 additions and 101 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features

- Add `main` flag to threads and `in_foreground` flag for app contexts ([#2516](https://github.com/getsentry/sentry-java/pull/2516))
- Add capabilities to track Jetpack Compose composition/rendering time ([#2507](https://github.com/getsentry/sentry-java/pull/2507))

### Fixes

Expand Down
4 changes: 4 additions & 0 deletions sentry-compose/api/android/sentry-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ public final class io/sentry/compose/BuildConfig {
public fun <init> ()V
}

public final class io/sentry/compose/SentryComposeTracingKt {
public static final fun SentryTraced (Ljava/lang/String;Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function3;Landroidx/compose/runtime/Composer;II)V
}

public final class io/sentry/compose/SentryNavigationIntegrationKt {
public static final fun withSentryObservableEffect (Landroidx/navigation/NavHostController;ZZLandroidx/compose/runtime/Composer;II)Landroidx/navigation/NavHostController;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package io.sentry.compose

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.platform.testTag
import io.sentry.Sentry
import io.sentry.SpanOptions

private const val OP_PARENT_COMPOSITION = "ui.compose.composition"
private const val OP_COMPOSE = "ui.compose"

private const val OP_PARENT_RENDER = "ui.compose.rendering"
private const val OP_RENDER = "ui.render"

@Immutable
private class ImmutableHolder<T>(var item: T)

private val localSentryCompositionParentSpan = compositionLocalOf {
ImmutableHolder(
Sentry.getRootSpan()
?.startChild(OP_PARENT_COMPOSITION, null, SpanOptions(true, true, true))
)
}

private val localSentryRenderingParentSpan = compositionLocalOf {
ImmutableHolder(
Sentry.getRootSpan()
?.startChild(OP_PARENT_RENDER, null, SpanOptions(true, true, true))
)
}

@ExperimentalComposeUiApi
@Composable
public fun SentryTraced(
tag: String,
modifier: Modifier = Modifier,
content: @Composable BoxScope.() -> Unit
) {
val parentCompositionSpan = localSentryCompositionParentSpan.current
val parentRenderingSpan = localSentryRenderingParentSpan.current
val compositionSpan = parentCompositionSpan.item?.startChild(OP_COMPOSE, tag)
val firstRendered = remember { ImmutableHolder(false) }

Box(
modifier = modifier
.testTag(tag)
.drawWithContent {
val renderSpan = if (!firstRendered.item) {
parentRenderingSpan.item?.startChild(
OP_RENDER,
tag
)
} else {
null
}
drawContent()
firstRendered.item = true
renderSpan?.finish()
}
) {
content()
}
compositionSpan?.finish()
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@file:OptIn(ExperimentalComposeUiApi::class)

package io.sentry.samples.android.compose

import android.os.Bundle
Expand All @@ -18,6 +20,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.input.TextFieldValue
Expand All @@ -28,8 +31,7 @@ import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import io.sentry.Sentry
import io.sentry.compose.withSentryObservableEffect
import io.sentry.compose.SentryTraced
import io.sentry.samples.android.GithubAPI
import kotlinx.coroutines.launch

Expand All @@ -43,48 +45,45 @@ class ComposeActivity : ComponentActivity() {
SampleNavigation(navController)
}
}

override fun onResume() {
super.onResume()
Sentry.getSpan()?.finish()
}
}

@Composable
fun Landing(
navigateGithub: () -> Unit,
navigateGithubWithArgs: () -> Unit
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Button(
onClick = {
navigateGithub()
},
modifier = Modifier
.testTag("button_nav_github")
.padding(top = 32.dp)
SentryTraced(tag = "buttons_page") {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text("Navigate to Github Page")
}
Button(
onClick = { navigateGithubWithArgs() },
modifier = Modifier
.testTag("button_nav_github_args")
.padding(top = 32.dp)
) {
Text("Navigate to Github Page With Args")
}
Button(
onClick = { throw RuntimeException("Crash from Compose") },
modifier = Modifier
.testTag("button_crash")
.padding(top = 32.dp)
) {
Text("Crash from Compose")
SentryTraced(tag = "button_nav_github") {
Button(
onClick = {
navigateGithub()
},
modifier = Modifier.padding(top = 32.dp)
) {
Text("Navigate to Github")
}
}
SentryTraced(tag = "button_nav_github_args") {
Button(
onClick = { navigateGithubWithArgs() },
modifier = Modifier.padding(top = 32.dp)
) {
Text("Navigate to Github Page With Args")
}
}
SentryTraced(tag = "button_crash") {
Button(
onClick = { throw RuntimeException("Crash from Compose") },
modifier = Modifier.padding(top = 32.dp)
) {
Text("Crash from Compose")
}
}
}
}
}
Expand All @@ -102,59 +101,67 @@ fun Github(
result = GithubAPI.service.listReposAsync(user.text, perPage).random().full_name
}

Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
TextField(
value = user,
onValueChange = { newText ->
user = newText
}
)
Text("Random repo $result")
Button(
onClick = {
scope.launch {
result = GithubAPI.service.listReposAsync(user.text, perPage).random().full_name
}
},
SentryTraced("github-$user") {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.testTag("button_list_repos_async")
.padding(top = 32.dp)
.fillMaxSize()
) {
Text("Make Request")
TextField(
value = user,
onValueChange = { newText ->
user = newText
}
)
Text("Random repo $result")
Button(
onClick = {
scope.launch {
result =
GithubAPI.service.listReposAsync(user.text, perPage).random().full_name
}
},
modifier = Modifier
.testTag("button_list_repos_async")
.padding(top = 32.dp)
) {
Text("Make Request")
}
}
}
}

@Composable
fun SampleNavigation(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = Destination.Landing.route
) {
composable(Destination.Landing.route) {
Landing(
navigateGithub = { navController.navigate("github") },
navigateGithubWithArgs = { navController.navigate("github/spotify?per_page=10") }
)
}
composable(Destination.Github.route) {
Github()
}
composable(
Destination.GithubWithArgs.route,
arguments = listOf(
navArgument(Destination.USER_ARG) { type = NavType.StringType },
navArgument(Destination.PER_PAGE_ARG) { type = NavType.IntType; defaultValue = 10 }
)
SentryTraced(tag = "navhost") {
NavHost(
navController = navController,
startDestination = Destination.Landing.route
) {
Github(
it.arguments?.getString(Destination.USER_ARG) ?: "getsentry",
it.arguments?.getInt(Destination.PER_PAGE_ARG) ?: 10
)
composable(Destination.Landing.route) {
Landing(
navigateGithub = { navController.navigate("github") },
navigateGithubWithArgs = { navController.navigate("github/spotify?per_page=10") }
)
}
composable(Destination.Github.route) {
Github()
}
composable(
Destination.GithubWithArgs.route,
arguments = listOf(
navArgument(Destination.USER_ARG) { type = NavType.StringType },
navArgument(Destination.PER_PAGE_ARG) {
type = NavType.IntType; defaultValue = 10
}
)
) {
Github(
it.arguments?.getString(Destination.USER_ARG) ?: "getsentry",
it.arguments?.getInt(Destination.PER_PAGE_ARG) ?: 10
)
}
}
}
}
Expand Down
Loading

0 comments on commit 17a5b01

Please sign in to comment.