Skip to content

Commit 6134075

Browse files
runningcodeclaude
andauthored
feat(samples): Make Android error buttons identifiable in Sentry (#5722)
Every button on the sample app's Errors tab sent generic, indistinguishable events (e.g. two buttons both threw "Uncaught Exception from Java." and "Send Message" sent "Some message."), so there was no way to tell which button produced which event in Sentry. Each Errors button now tags its event with sample_action=<button key> (reusing the existing SentryTraced keys) and uses distinctive text that names the button. Buttons whose crash carries no message (stack overflow, OOM, native) are still identifiable via the tag. The native captured message is likewise renamed. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 066c6ca commit 6134075

2 files changed

Lines changed: 88 additions & 15 deletions

File tree

sentry-samples/sentry-samples-android/src/main/cpp/native-sample.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ JNIEXPORT void JNICALL Java_io_sentry_samples_android_NativeSample_message(JNIEn
1717
sentry_value_t event = sentry_value_new_message_event(
1818
/* level */ SENTRY_LEVEL_INFO,
1919
/* logger */ "custom",
20-
/* message */ "It works!"
20+
/* message */ "Native Capture button: native message"
2121
);
2222
sentry_capture_event(event);
2323
}

sentry-samples/sentry-samples-android/src/main/java/io/sentry/samples/android/MainActivity.kt

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,17 @@ import androidx.compose.foundation.layout.Arrangement
2323
import androidx.compose.foundation.layout.PaddingValues
2424
import androidx.compose.foundation.layout.Row
2525
import androidx.compose.foundation.layout.Spacer
26+
import androidx.compose.foundation.layout.WindowInsets
27+
import androidx.compose.foundation.layout.WindowInsetsSides
2628
import androidx.compose.foundation.layout.defaultMinSize
2729
import androidx.compose.foundation.layout.fillMaxHeight
2830
import androidx.compose.foundation.layout.fillMaxSize
2931
import androidx.compose.foundation.layout.height
32+
import androidx.compose.foundation.layout.only
3033
import androidx.compose.foundation.layout.padding
34+
import androidx.compose.foundation.layout.safeDrawing
3135
import androidx.compose.foundation.layout.size
36+
import androidx.compose.foundation.layout.windowInsetsPadding
3237
import androidx.compose.foundation.lazy.grid.GridCells
3338
import androidx.compose.foundation.lazy.grid.GridItemSpan
3439
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
@@ -184,11 +189,21 @@ fun MainScreen() {
184189

185190
Surface(modifier = Modifier.fillMaxSize()) {
186191
Row(modifier = Modifier.fillMaxSize()) {
192+
// NavigationRail already draws its background edge-to-edge (behind the status bar) while
193+
// insetting its own items, so we only need to inset the content area on the remaining sides.
187194
CategoryNavigationRail(
188195
selectedCategory = selectedCategory,
189196
onCategorySelected = { selectedCategory = it },
190197
)
191-
Surface(modifier = Modifier.fillMaxSize()) {
198+
Surface(
199+
modifier =
200+
Modifier.fillMaxSize()
201+
.windowInsetsPadding(
202+
WindowInsets.safeDrawing.only(
203+
WindowInsetsSides.Top + WindowInsetsSides.Bottom + WindowInsetsSides.End
204+
)
205+
)
206+
) {
192207
when (selectedCategory) {
193208
Category.ERRORS -> ErrorsScreen()
194209
Category.TRACING -> TracingScreen()
@@ -271,15 +286,25 @@ fun ErrorsScreen() {
271286
) {
272287
item {
273288
SentryTraced("crash_from_java") {
274-
OutlinedButton(onClick = { throw RuntimeException("Uncaught Exception from Java.") }) {
289+
OutlinedButton(
290+
onClick = {
291+
tagSampleAction("crash_from_java")
292+
throw RuntimeException("Crash from Java button: uncaught RuntimeException")
293+
}
294+
) {
275295
Text("Crash from Java", maxLines = 2, overflow = TextOverflow.Ellipsis)
276296
}
277297
}
278298
}
279299
item {
280300
SentryTraced("capture_exception") {
281301
OutlinedButton(
282-
onClick = { Sentry.captureException(Exception(Exception(Exception("Some exception.")))) },
302+
onClick = {
303+
tagSampleAction("capture_exception")
304+
Sentry.captureException(
305+
Exception(Exception(Exception("Capture Exception button: nested exception")))
306+
)
307+
},
283308
modifier = Modifier,
284309
) {
285310
Text("Capture Exception", maxLines = 2, overflow = TextOverflow.Ellipsis)
@@ -290,11 +315,12 @@ fun ErrorsScreen() {
290315
SentryTraced("breadcrumb") {
291316
OutlinedButton(
292317
onClick = {
293-
Sentry.addBreadcrumb("Breadcrumb")
318+
tagSampleAction("breadcrumb")
319+
Sentry.addBreadcrumb("Breadcrumb button clicked")
294320
Sentry.setExtra("extra", "extra")
295321
Sentry.setFingerprint(listOf("fingerprint"))
296322
Sentry.setTransaction("transaction")
297-
Sentry.captureException(Exception("Some exception with scope."))
323+
Sentry.captureException(Exception("Breadcrumb button: exception with scope data"))
298324
},
299325
modifier = Modifier,
300326
) {
@@ -304,21 +330,39 @@ fun ErrorsScreen() {
304330
}
305331
item {
306332
SentryTraced("stack_overflow") {
307-
OutlinedButton(onClick = { stackOverflow() }, modifier = Modifier) {
333+
OutlinedButton(
334+
onClick = {
335+
tagSampleAction("stack_overflow")
336+
stackOverflow()
337+
},
338+
modifier = Modifier,
339+
) {
308340
Text("Stack Overflow", maxLines = 2, overflow = TextOverflow.Ellipsis)
309341
}
310342
}
311343
}
312344
item {
313345
SentryTraced("native_crash") {
314-
OutlinedButton(onClick = { NativeSample.crash() }, modifier = Modifier) {
346+
OutlinedButton(
347+
onClick = {
348+
tagSampleAction("native_crash")
349+
NativeSample.crash()
350+
},
351+
modifier = Modifier,
352+
) {
315353
Text("Native Crash", maxLines = 2, overflow = TextOverflow.Ellipsis)
316354
}
317355
}
318356
}
319357
item {
320358
SentryTraced("native_capture") {
321-
OutlinedButton(onClick = { NativeSample.message() }, modifier = Modifier) {
359+
OutlinedButton(
360+
onClick = {
361+
tagSampleAction("native_capture")
362+
NativeSample.message()
363+
},
364+
modifier = Modifier,
365+
) {
322366
Text("Native Capture", maxLines = 2, overflow = TextOverflow.Ellipsis)
323367
}
324368
}
@@ -327,6 +371,7 @@ fun ErrorsScreen() {
327371
SentryTraced("anr") {
328372
OutlinedButton(
329373
onClick = {
374+
tagSampleAction("anr")
330375
Thread {
331376
synchronized(mutex) {
332377
while (true) {
@@ -341,7 +386,14 @@ fun ErrorsScreen() {
341386
.start()
342387

343388
Handler(Looper.getMainLooper())
344-
.postDelayed({ synchronized(mutex) { throw IllegalStateException() } }, 1000)
389+
.postDelayed(
390+
{
391+
synchronized(mutex) {
392+
throw IllegalStateException("ANR button: main thread blocked")
393+
}
394+
},
395+
1000,
396+
)
345397
},
346398
modifier = Modifier,
347399
) {
@@ -353,10 +405,18 @@ fun ErrorsScreen() {
353405
SentryTraced("native_anr") {
354406
OutlinedButton(
355407
onClick = {
408+
tagSampleAction("native_anr")
356409
Thread { NativeSample.freezeMysteriously(mutex) }.start()
357410

358411
Handler(Looper.getMainLooper())
359-
.postDelayed({ synchronized(mutex) { throw IllegalStateException() } }, 1000)
412+
.postDelayed(
413+
{
414+
synchronized(mutex) {
415+
throw IllegalStateException("ANR (native) button: main thread blocked")
416+
}
417+
},
418+
1000,
419+
)
360420
},
361421
modifier = Modifier,
362422
) {
@@ -368,6 +428,7 @@ fun ErrorsScreen() {
368428
SentryTraced("out_of_memory") {
369429
OutlinedButton(
370430
onClick = {
431+
tagSampleAction("out_of_memory")
371432
val latch = CountDownLatch(1)
372433
for (i in 0 until 20) {
373434
Thread {
@@ -393,7 +454,13 @@ fun ErrorsScreen() {
393454
}
394455
item {
395456
SentryTraced("send_message") {
396-
OutlinedButton(onClick = { Sentry.captureMessage("Some message.") }, modifier = Modifier) {
457+
OutlinedButton(
458+
onClick = {
459+
tagSampleAction("send_message")
460+
Sentry.captureMessage("Send Message button: test message")
461+
},
462+
modifier = Modifier,
463+
) {
397464
Text("Send Message", maxLines = 2, overflow = TextOverflow.Ellipsis)
398465
}
399466
}
@@ -402,11 +469,12 @@ fun ErrorsScreen() {
402469
SentryTraced("test_timber") {
403470
OutlinedButton(
404471
onClick = {
472+
tagSampleAction("test_timber")
405473
crashCount.intValue++
406-
Timber.i("Some info here")
474+
Timber.i("Test Timber button: info log")
407475
Timber.e(
408-
RuntimeException("Uncaught Exception from Java."),
409-
"Something wrong happened ${crashCount.intValue} times",
476+
RuntimeException("Test Timber button: error RuntimeException"),
477+
"Test Timber button: error logged ${crashCount.intValue} times",
410478
)
411479
},
412480
modifier = Modifier,
@@ -935,3 +1003,8 @@ fun Context.getActivity(): ComponentActivity {
9351003
fun stackOverflow() {
9361004
stackOverflow()
9371005
}
1006+
1007+
private fun tagSampleAction(action: String) {
1008+
// Tag every event with the button that triggered it so it can be filtered in Sentry.
1009+
Sentry.setTag("sample_action", action)
1010+
}

0 commit comments

Comments
 (0)