In order to understand what happened in your application before each error, it can be helpful to leave short log statements that we call breadcrumbs. A configurable number of breadcrumbs are attached to each error report to help diagnose what events led to the error.
This documentation is for version 5+ of the BugSnag Android notifier. If you are using older versions, we recommend upgrading to the latest release using our Upgrade guide. Documentation for the previous release can be found on our legacy pages.
By default, BugSnag captures breadcrumbs for common actions and device changes, including:
This can be controlled using the enabledBreadcrumbTypes
configuration option.
BugSnag can capture network requests from the OkHttp library as breadcrumbs. These are attached to each error report to help diagnose what events led to the error:
BugSnag will capture any HTTP calls made via the OkHttp library. Each will be shown as ended, failed or cancelled.
To capture network breadcrumbs, add bugsnag-plugin-android-okhttp
as a dependency to your project:
dependencies {
implementation "com.bugsnag:bugsnag-android:6.+"
implementation "com.bugsnag:bugsnag-plugin-android-okhttp:6.+"
implementation "com.squareup.okhttp3:okhttp:4.+"
}
dependencies {
implementation("com.bugsnag:bugsnag-android:6.+")
implementation("com.bugsnag:bugsnag-plugin-android-okhttp:6.+")
implementation("com.squareup.okhttp3:okhttp:4.+")
}
BugSnag supports both OkHttp 3 and 4.
Then configure BugSnag to start with BugsnagOkHttpPlugin
:
BugsnagOkHttpPlugin bugsnagOkHttpPlugin = new BugsnagOkHttpPlugin();
Configuration config = Configuration.load(this);
config.addPlugin(bugsnagOkHttpPlugin);
Bugsnag.start(this, config);
val bugsnagOkHttpPlugin = BugsnagOkHttpPlugin()
Bugsnag.start(this, Configuration.load(this).apply {
addPlugin(bugsnagOkHttpPlugin)
})
Finally, register this BugsnagOkHttpPlugin
instance to listen to events for all OkHttpClient
objects in your app (ensure you are passing the same BugsnagOkHttpPlugin
object to both BugSnag and OkHttp):
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.eventListener(bugsnagOkHttpPlugin)
.build();
val okHttpClient = OkHttpClient.Builder()
.eventListener(bugsnagOkHttpPlugin)
.build()
The OkHttp response body must be closed for breadcrumbs to be captured. Failing to close the body is an error that will leak resources within OkHttp.
For performance reasons, the value reported for responseContentLength
in breadcrumb metadata will be 0
if the OkHttp response body has not been read.
Append manual breadcrumbs with a message via the Bugsnag
client:
Bugsnag.leaveBreadcrumb("App loaded");
Bugsnag.leaveBreadcrumb("User clicked a button");
Bugsnag.leaveBreadcrumb("App loaded")
Bugsnag.leaveBreadcrumb("User clicked a button")
bugsnag_leave_breadcrumb_env(env, "App loaded", BSG_CRUMB_MANUAL);
BugSnag will keep track of the time and order of the breadcrumbs, and show them on your dashboard.
Additional data can be attached to breadcrumbs by providing the additional metadata
argument. Metadata will be presented on the BugSnag dashboard alongside the breadcrumb name and type:
Map<String, Object> metadata = new HashMap<String, Object>() {{
put("from", "moka");
put("to", "french press");
}};
Bugsnag.leaveBreadcrumb("Preference updated", metadata, BreadcrumbType.STATE);
val metadata = mapOf(
"from" to "moka",
"to" to "french press"
)
Bugsnag.leaveBreadcrumb("Preference updated", metadata, BreadcrumbType.STATE)
// There is no equivalent operation in C/C++
Breadcrumb “types” can be used to differentiate different types of events, such as user activity and changes in application state. See the BreadcrumbType
enumeration for a complete list of the breadcrumb types available to Java or Kotlin code, and the Native API header for C/C++ code. Your breadcrumbs will not be affected by the enabledBreadcrumbTypes
configuration option.
For NDK errors, the event metadata and the metadata on each breadcrumb will be restricted to 128 entries and 63-character keys. Any additional data will be truncated.
If you wish to log breadcrumbs for the Fragment Lifecycle, we suggest that you use
FragmentLifecycleCallbacks
for all the activities which you wish to track.
public class MyActivity extends FragmentActivity {
@Override
protected void onStart() {
super.onStart();
getSupportFragmentManager()
.registerFragmentLifecycleCallbacks(new FragmentBreadcrumbLogger(), true);
}
}
public class FragmentBreadcrumbLogger extends FragmentManager.FragmentLifecycleCallbacks {
private static final String FRAG_LIFECYCLE_CALLBACK = "FragmentLifecycleCallback";
@Override
public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
leaveLifecycleBreadcrumb(f, "onFragmentCreated()");
}
// leave Breadcrumbs in other lifecycle callbacks if needed
private void leaveLifecycleBreadcrumb(Fragment fragment, String lifecycleCallback) {
// note - if proguard is enabled you may want to use a different method of obtaining
// the current fragment's name
String fragmentName = fragment.getClass().getSimpleName();
Map<String, Object> metadata = new HashMap<>();
metadata.put(FRAG_LIFECYCLE_CALLBACK, lifecycleCallback);
Bugsnag.leaveBreadcrumb(fragmentName, metadata, BreadcrumbType.NAVIGATION);
}
}
class MyActivity : FragmentActivity() {
override fun onStart() {
super.onStart()
supportFragmentManager
.registerFragmentLifecycleCallbacks(FragmentBreadcrumbLogger(), true)
}
}
class FragmentBreadcrumbLogger : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(fm: FragmentManager?, f: Fragment?, savedInstanceState: Bundle?) {
f?.let { leaveLifecycleBreadcrumb(it, "onFragmentCreated()") }
}
// leave Breadcrumbs in other lifecycle callbacks if needed
private fun leaveLifecycleBreadcrumb(fragment: Fragment, lifecycleCallback: String) {
// note - if proguard is enabled you may want to use a different method of obtaining
// the current fragment's name
val fragmentName = fragment.javaClass.simpleName
val metadata = HashMap<String, Object>()
metadata.put("FragmentLifecycleCallback", lifecycleCallback)
Bugsnag.leaveBreadcrumb(fragmentName, metadata, BreadcrumbType.NAVIGATION)
}
}
You can register a callback that is executed each time a breadcrumb is captured using the addOnBreadcrumb
configuration option. This can be helpful if you wish to filter out certain automatic breadcrumbs from your application or amend the data contained within them.
Configuration config = Configuration.load(this);
config.addOnBreadcrumb(new OnBreadcrumbCallback() {
@Override
public boolean onBreadcrumb(@NonNull Breadcrumb breadcrumb) {
if (breadcrumb.getMessage().equals("Noisy breadcrumb")) {
return false; // ignore the breadcrumb
} else {
return true; // capture the breadcrumb
}
}
});
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
addOnBreadcrumb(OnBreadcrumbCallback { breadcrumb ->
if (breadcrumb.message == "Noisy breadcrumb") {
false // ignore the breadcrumb
} else {
true // capture the breadcrumb
}
}
})
// There is no equivalent operation in C/C++
We recommend adding callbacks through the addOnBreadcrumb
configuration option to ensure that it is registered as soon as BugSnag starts. However, the following methods are provided to allow callbacks to be added and removed whilst the application is running:
OnBreadcrumbCallback cb = new OnBreadcrumbCallback() { /* ... */ };
Bugsnag.addOnBreadcrumb(cb);
// ...
Bugsnag.removeOnBreadcrumb(cb);
val cb = OnBreadcrumbCallback { /* ... */ }
Bugsnag.addOnBreadcrumb(cb)
// ...
Bugsnag.removeOnBreadcrumb(cb)
// There is no equivalent operation in C/C++
Breadcrumb
classThe following information is available on the Breadcrumb
class, the representation of breadcrumb information available in an OnBreadcrumbCallback
. See the Breadcrumb
class for full documentation.
property | type | description |
---|---|---|
message |
String |
The description of the breadcrumb |
metadata |
Map<String, Any?> |
Diagnostic data relating to the breadcrumb |
timestamp |
Date |
The timestamp that the breadcrumb was left |
type |
BreadcrumbType |
The type of breadcrumb left |