Error Tracking aggregates the errors reported by your Android application into issues, grouping occurrences that share a root cause so a crash affecting a thousand users is one entry rather than a thousand. Each issue carries a stack trace, the device, OS, and app version distribution it occurs across, and a link to the RUM session that produced it.
This page covers what the SDK reports, how to configure each error source, and how to make obfuscated release traces readable.
What is reported
With RUM enabled, the SDK collects four classes of error:
- Crashes, uncaught exceptions that terminate the process, captured through the JVM's default uncaught exception handler.
- ANRs, raised when the main thread is blocked long enough for the system to consider the application unresponsive.
- Network errors, for requests that fail or return an error status on hosts instrumented by
AtatusInterceptor. - Handled exceptions, reported explicitly through
addError.
Every error is attributed to the view and session active when it occurred, so an issue resolves to the user journey that produced it rather than a stack trace in isolation.
Prerequisites
The SDK must be initialized and RUM enabled. See Android Monitoring Setup.
Report crashes
Crash reporting is enabled by default and requires no configuration beyond the base integration. Set it explicitly to document the intent, or to disable it where another handler owns the process:
val configuration = Configuration.Builder(
licenseKey = "<LICENSE_KEY>",
env = "<ENV_NAME>",
variant = "<APP_VARIANT_NAME>"
)
.setCrashReportsEnabled(true)
.build()
A crash is persisted to disk as the process terminates and uploaded on the next launch, since the SDK has no opportunity to complete a network request while the process is being torn down.
Report ANRs
Fatal ANRs, where the system terminates the application, are reported automatically. Non-fatal ANRs, where the main thread recovers after blocking, are disabled by default because their volume varies widely between applications:
val rumConfiguration = RumConfiguration.Builder()
.trackNonFatalAnrs(true)
.build()
Non-fatal ANRs and long tasks share a cause: work scheduled on the main thread that belongs on a background dispatcher. If ANR volume is high, correlate it with long tasks to locate the blocking call sites.
Report handled exceptions
addError promotes an exception you caught into a RUM error event, so failures your application degrades gracefully around are still measurable:
import com.atatus.android.rum.GlobalRumMonitor
import com.atatus.android.rum.RumErrorSource
try {
processPayment(order)
} catch (e: PaymentException) {
GlobalRumMonitor.get().addError(
message = "Payment failed",
source = RumErrorSource.SOURCE,
throwable = e,
attributes = mapOf("order.id" to order.id)
)
}
Always pass the Throwable when one is available. Issue grouping is derived from the stack trace, so errors reported without one collapse on message alone and group far less precisely.
The source classifies where the error originated and determines how it is categorized in your dashboard:
| Source | Applies to |
|---|---|
SOURCE |
Exceptions raised by your own application code. |
NETWORK |
Failures originating from a network request. |
WEBVIEW |
Errors propagated from embedded web content. |
CONSOLE |
Errors captured from console output. |
Deobfuscate release stack traces
R8 and ProGuard rename classes and methods during release builds, leaving production stack traces unreadable. Uploading the mapping file lets Atatus restore the original symbols server-side, so the obfuscated build you ship stays diagnosable.
After a release build, the mapping file is written to:
app/build/outputs/mapping/release/mapping.txt
Upload it from your RUM application settings in the Atatus dashboard, matching the version name and build number of the release it was produced for.
Upload a mapping file for every release you ship. R8 generates a distinct mapping per build, so a trace from version 2.1 cannot be resolved against the mapping from 2.0, and any release without an upload remains obfuscated permanently.
Preserve line number metadata so deobfuscated traces resolve to source lines rather than method names alone:
-keepattributes SourceFile,LineNumberTable
Filter out noisy errors
Some failures are expected and carry no diagnostic value, such as requests cancelled when a user navigates away mid-flight. Discard them with an error event mapper, which runs before serialization:
val rumConfiguration = RumConfiguration.Builder()
.setErrorEventMapper { event ->
if (event.error.message?.contains("Canceled") == true) null else event
}
.build()
Returning null drops the event. Crash events are exempt from this filter, since suppressing them would conceal fatal failures.
Next steps
- Locate the main-thread work behind ANRs with long task tracking.
- Attach domain context to errors using global attributes.
- Capture errors raised inside embedded web content with WebView Tracking.
+1-415-800-4104