Customizing breadcrumbs

This guide explains adding custom breadcrumbs to improve error reproduction steps and removing unneeded automatic breadcrumbs.

In order to understand what happened in your application before each crash, it can be helpful to leave short log statements that we call breadcrumbs. Breadcrumbs are attached to the reported event to help diagnose what 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.

Automatic breadcrumbs

By default, Bugsnag captures breadcrumbs for common actions and device changes, including:

  • Activity Lifecycle callbacks
  • Network connectivity changes
  • Bluetooth connectivity changes
  • Battery state changes
  • Device rotation
  • Media Scanner events
  • Telephony events
  • Other device metrics and more

This can be controlled using the enabledBreadcrumbTypes configuration option.

Adding manual breadcrumbs

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);

The notifier tracks the time when a breadcrumb is logged, and shows the message and timestamp on your dashboard.

Attaching metadata

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 value.

Tracking fragment lifecycles

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.

Example: Using FragmentLifecycleCallbacks to log navigation events

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)
    }
}

Discarding and amending breadcrumbs

You can register a callback that is executed each time a breadcrumb is captured using addOnBreadcrumb. 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);
val config = Configuration.load(this)
config.addOnBreadcrumb(OnBreadcrumbCallback { breadcrumb ->
    if (breadcrumb.message == "Noisy breadcrumb") {
        false // ignore the breadcrumb
    } else {
        true // capture the breadcrumb
    }
}
Bugsnag.start(this, config)
// There is no equivalent operation in C/C++

Adding and removing callbacks

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++

The Breadcrumb class

The 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