In order to quickly reproduce and fix errors, it is often helpful to send additional application-specific diagnostic data to your BugSnag dashboard to provide a rich context that is also available for searching and filtering.
You can also amend the events captured by BugSnag to adjust the information shown on the dashboard and even choose not to send the event at all.
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.
If you’d like to add diagnostic data to reports, or adjust event data conditionally, you can use an OnErrorCallback
, which will be run immediately after an error is captured or reported:
Configuration config = Configuration.load(this);
config.addOnError(new OnErrorCallback() {
@Override
public boolean onError(Event event) {
event.addMetadata("account", "name", "Acme Co.");
event.addMetadata("account", "paying_customer", true);
// Return `false` if you'd like to stop this error being reported
return true;
}
});
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
addOnError(OnErrorCallback { event ->
event.addMetadata("account", "name", "Acme Co.")
event.addMetadata("account", "paying_customer", true)
// Return `false` if you'd like to stop this error being reported
true
})
})
The callback gives you access to the Event object, so you can inspect and modify the error event which is about to be sent to BugSnag.
OnErrorCallback
s set in Java/Kotlin are executed for handled errors sent from native C/C++ code, but they will not be triggered for native crashes as the system terminates immediately in that case.
See the expandable sections immediately below for details on how to add a delivery time callback function that will be run for all errors, and for details on how to add a C/C++ callback function for unhandled native errors only.
You can use an OnSendCallback
to modify or discard error events where callbacks cannot be invoked at the time of the error:
Configuration config = Configuration.load(this);
config.addOnSend(new OnSendCallback() {
@Override
public boolean onSend(Event event) {
event.addMetadata("account", "name", "Acme Co.");
event.addMetadata("account", "paying_customer", true);
// Return `false` if you'd like to stop this error being reported
return true;
}
});
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
addOnSend(OnSendCallback { event ->
event.addMetadata("account", "name", "Acme Co.")
event.addMetadata("account", "paying_customer", true)
// Return `false` if you'd like to stop this error being reported
true
})
})
For native crashes or errors that occur when the app is offline, the error will usually be sent when the app next launches. To avoid misleading error reports, avoid using this callback to attach transient information.
Changing an event’s isUnhandled
property in an OnSendCallback
will not affect the unhandled event count against the session and therefore will not have the expected impact on stability. An OnErrorCallback
should be used instead when changing the isUnhandled
property.
Due to the limitations on the code that can be run when handling a crash signal on the NDK layer, unhandled events from the NDK layer are always serialised to disk and sent when the app next launches.
In order to register a callback that executes at the time of the crash, use the bugsnag_add_on_error
method to pass in a callback function:
bool custom_on_error_callback(void *event) {
bugsnag_event_add_metadata_string(event, "account", "name", "Acme Co.");
bugsnag_event_add_metadata_bool(event, "account", "paying_customer", true);
// Return `false` if you'd like to stop this error being reported
return true;
}
bugsnag_add_on_error(&custom_on_error_callback);
Care must be taken to ensure that the callback function provided is async-signal safe. The code will be executed in an asynchronous signal handler and so must not call any functions that are not Async-Signal-Safe. Further information can be found here.
Most of the fields in the Event
class in the JVM are available in this callback using a set of functions (see event.h) that take the event
pointer argument and either return data from the event or allow you to set it. Examples are given alongside the Event class field below.
We recommend adding callbacks through the addOnError
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:
OnErrorCallback cb = new OnErrorCallback() { /* ... */ };
Bugsnag.addOnError(cb);
// ...
Bugsnag.removeOnError(cb);
val cb = OnErrorCallback { /* ... */ }
Bugsnag.addOnError(cb)
// ...
Bugsnag.removeOnError(cb)
bugsnag_add_on_error(&custom_on_error_callback);
bugsnag_remove_on_error();
If you want to prevent an event from being sent to BugSnag, you can return false within an onError
.
This would allow for users to opt out of sending error reports, for example:
Configuration config = Configuration.load(this);
config.addOnError(new OnErrorCallback() {
@Override
public boolean onError(Event event) {
return !userHasOptedOut();
}
});
Bugsnag.start(this, config);
val config = Configuration.load(this)
config.addOnError(OnErrorCallback { event ->
!userHasOptedOut()
}
Bugsnag.start(this, config)
bool custom_on_error_callback(void *event) {
return !userHasOptedOut();
}
bugsnag_add_on_error(&custom_on_error_callback);
If you have metadata that is applicable to all captured events, it can be set globally on the Bugsnag
client and will be set on all subsequently generated events. To ensure that events contain metadata as soon as BugSnag starts capturing events, use the addMetadata
functions on the Configuration
class.
Data is added to a specified “section”, which is displayed as a tab in the BugSnag dashboard, and can either be added individually or as a map of key-value pairs:
Configuration config = Configuration.load(this);
config.addMetadata("account", "name", "Acme Co.");
config.addMetadata("basket", new HashMap<String, Object>() {{
put("delivery", "express");
put("sale", "spring");
}});
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
addMetadata("account", "name", "Acme Co.")
addMetadata("basket", hashMapOf(
"delivery" to "express",
"sale" to "spring"
))
})
// There is no equivalent operation for adding global metadata in C/C++.
// Metadata can be added through the on_error callback for each event or
// added to the `Bugsnag` client.
Metadata can also be managed whilst your application is running using addMetadata
and clearMetadata
on the Bugsnag
client:
Bugsnag.addMetadata("account", "name", "Acme Co.");
// ...
Bugsnag.clearMetadata("account");
Bugsnag.addMetadata("account", "name", "Acme Co.")
// ...
Bugsnag.clearMetadata("account");
// There is no equivalent operation for adding global metadata in C/C++.
// Metadata can be added through the on_error callback for each event or
// added to the `Bugsnag` client.
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.
Information about the user affected by errors can be added to events sent to your BugSnag dashboard by setting an initial user ID, email and name in Configuration when BugSnag starts:
Configuration config = Configuration.load(this);
config.setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag");
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag")
})
When the persistUser
configuration option is set to true
, this user information will also be set in subsequent application launches.
If the user changes whilst the application is running, for example if a user signs in, you can update the user data on the BugSnag client for all subsequent events:
Bugsnag.setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag");
Bugsnag.setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag")
bugsnag_set_user_env(env, "3", "bugs.nag@bugsnag.com", "Bugs Nag");
Alternatively, you can set the user for each event through an OnErrorCallback
:
Configuration config = Configuration.load(this);
config.addOnError(new OnErrorCallback() {
@Override
public boolean onError(Event event) {
event.setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag");
return true;
}
});
Bugsnag.start(this, config);
val config = Configuration.load(this)
config.addOnError(OnErrorCallback { event ->
event.setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag")
true
}
Bugsnag.start(this, config)
bool custom_on_error_callback(void *event) {
bugsnag_event_set_user(event, "3", "bugs.nag@bugsnag.com", "Bugs Nag")
return true;
}
bugsnag_add_on_error(&custom_on_error_callback);
You can use metadata to add additional user information to the “user” section.
BugSnag uses the concept of “contexts” to help display and group your errors. The context represents what was happening in your application at the time an error occurs and is given high visual prominence in the dashboard.
By default this is set this to the foreground Activity
. If you would like to set this value manually, you can set an initial value in Configuration when BugSnag starts:
Configuration config = Configuration.load(this);
config.setContext("InitialTutorialStep");
Bugsnag.start(this, config);
Bugsnag.start(this, Configuration.load(this).apply {
context = "InitialTutorialStep"
})
The context can then be amended on the Bugsnag
client as/when it changes for all subsequent events:
Bugsnag.setContext("SecondTutorialStep");
Bugsnag.setContext("SecondTutorialStep")
// There is no equivalent operation for adding global context in C/C++.
// Context can be added through the on_error callback for each event or
// added to the `Bugsnag` client.
Context added to the Bugsnag
client is synchronized with the NDK layer and so will also appear in native crash reports.
Alternatively, the context can be amended for each event using an OnErrorCallback
:
Configuration config = Configuration.load(this);
config.addOnError(new OnErrorCallback() {
@Override
public boolean onError(Event event) {
event.setContext("SecondTutorialStep");
return true;
}
});
Bugsnag.start(this, config);
val config = Configuration.load(this)
config.addOnError(OnErrorCallback { event ->
event.context = "SecondTutorialStep"
true
}
Bugsnag.start(this, config)
bool custom_on_error_callback(void *event) {
bugsnag_event_set_context(event, "SecondTutorialStep");
return true;
}
bugsnag_add_on_error(&custom_on_error_callback);
Event
classAn Event
object represents an error captured by BugSnag and is available as a parameter on an OnErrorCallback
. The following properties and methods are available on an Event
for you to query and update the captured data — see the Javadoc for full documentation.
addFeatureFlag
Declare a single feature flag or experiment with variant as an optional second parameter.
event.addFeatureFlag("Checkout button color", "Blue");
event.addFeatureFlag("New checkout flow");
event.addFeatureFlag("Checkout button color", "Blue")
event.addFeatureFlag("New checkout flow")
// There is no equivalent operation in C/C++
For more information, see Feature flags & experiments.
addFeatureFlags
Declare multiple feature flags or experiments.
event.addFeatureFlags(Arrays.asList(
new FeatureFlag("Checkout button color", "Blue"),
new FeatureFlag("Special offer", "Free Coffee"),
new FeatureFlag("New checkout flow")
));
event.addFeatureFlags(listOf(
FeatureFlag("Checkout button color", "Blue"),
FeatureFlag("Special offer", "Free Coffee"),
FeatureFlag("New checkout flow")
))
// There is no equivalent operation in C/C++
For more information, see Feature flags & experiments.
addMetadata
Adds the specified key and value in the specified section, which is shown as a tab on the BugSnag dashboard.
Data can be added key-by-key with a value that is a primitive type or a collection such as a map, set or array:
event.addMetadata("account", "name", "Acme Co.");
event.addMetadata("account", "paying_customer", true);
event.addMetadata("account", "roles", new HashSet<String>() {{
add("basic");
add("admin");
}});
event.addMetadata("account", "name", "Acme Co.")
event.addMetadata("account", "paying_customer", true)
event.addMetadata("account", "roles", setOf("basic", "admin"))
bugsnag_event_add_metadata_string(event, "account", "name", "Acme Co.");
Alternatively a whole map of key-value pairs can be added for a section:
event.addMetadata("basket", new HashMap<String, Object>() {{
put("delivery", "express");
put("sale", "spring");
}});
event.addMetadata("basket", mapOf(
"delivery" to "express",
"sale" to "spring"
))
// There is no equivalent operation in C/C++
Metadata set on the event will be combined with global metadata set on the Bugsnag
client, with properties on the Event
taking precedence.
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.
apiKey
The API key used for events sent to BugSnag. Even though the API key is set when BugSnag is initialized, you may choose to send certain events to a different BugSnag project:
String apiKey = event.getApiKey();
var apiKey = event.apiKey
// There is no equivalent operation in C/C++
app
Information set by the notifier about your app can be found in the app
object:
property | type | description |
---|---|---|
binaryArch |
String |
The architecture of the running application binary |
buildUuid |
String |
The unique identifier for the build of the application set in Configuration |
codeBundleId |
String |
The revision ID from the manifest (React Native apps only) |
duration |
Number |
The number of milliseconds the application was running before the event occurred |
durationInForeground |
Number |
The number of milliseconds the application was running in the foreground before the event occurred |
id |
String |
The package name of the application |
inForeground |
Boolean |
Whether the application was in the foreground when the event occurred |
isLaunching |
Boolean |
Whether the application was still launching when the event occurred |
releaseStage |
String |
The release stage set in Configuration |
type |
String |
The application type set in Configuration |
version |
String |
The version of the application set in Configuration |
versionCode |
Number |
The version code of the application set in Configuration |
These values can be accessed and amended if necessary:
event.getApp().setBuildUuid(getBuildNumber());
event.app.buildUuid = getBuildNumber()
bugsnag_app_set_build_uuid(event, getBuildNumber());
breadcrumbs
A list of breadcrumbs leading up to the event can be found in event.breadcrumbs
. See the Breadcrumb
class for details of the data available.
These values can be accessed and amended if necessary:
event.getBreadcrumbs().get(0).setMessage("Left home screen");
event.breadcrumbs[0].message = "Left home screen";
// There is no equivalent operation in C/C++
clearFeatureFlag
Remove a single feature flag or experiment.
event.clearFeatureFlag("Checkout button color");
event.clearFeatureFlag("Checkout button color")
// There is no equivalent operation in C/C++
For more information, see Feature flags & experiments.
clearFeatureFlags
Remove all feature flags and experiments.
event.clearFeatureFlags();
event.clearFeatureFlags()
// There is no equivalent operation in C/C++
For more information, see Feature flags & experiments.
clearMetadata
Removes all the data from the specified section or from a key in the section:
event.clearMetadata("account");
// or
event.clearMetadata("account", "name");
event.clearMetadata("account")
// or
event.clearMetadata("account", "name")
bugsnag_event_clear_metadata(event, "account", "name");
// or
bugsnag_event_clear_metadata_section(event, "account");
context
The context represents what was happening in your application at the time an error occurs.
event.setContext("User settings");
event.context = "User settings"
bugsnag_event_set_context(event, "User settings");
See Setting context for more information.
device
Information set by the notifier about the device on which the event occurred can be found in event.device
:
property | type | description |
---|---|---|
cpuAbi |
String[] |
The Application Binary Interface used |
freeDisk |
Number |
The number of free bytes of storage available on the device |
freeMemory |
Number |
The available RAM on the device (in bytes) |
id |
String |
A UUID generated by BugSnag and used for the individual application on a device |
jailbroken |
String |
Whether the device has been jailbroken |
locale |
String |
The IETF language tag of the locale used |
manufacturer |
String |
The manufacturer of the device used |
model |
String |
The model name of the device used |
orientation |
String |
The orientation of the device when the event occurred: either portrait or landscape |
osName |
String |
The name of the operating system running on the device used |
osVersion |
String |
The version of the operating system running on the device used |
runtimeVersions |
Map |
A collection of names and their versions of the primary languages, frameworks or runtimes that the application is running on |
time |
String |
The timestamp on the device when the event occurred |
totalMemory |
Number |
The total RAM size of the device (in bytes) |
These values can be accessed and amended if necessary:
event.getDevice().setLocale("de-DE");
event.device.locale = "de-DE"
bugsnag_device_set_locale(event, "de-DE");
errors
event.errors
is an array of one or more Error
objects. The first item in the list represents the thrown object. Each subsequent item represents the exception that caused the preceding one.
A reference to the actual Throwable
object that caused the event is available through event.originalError
.
An Error
object contains the following information:
property | type | description |
---|---|---|
errorClass |
String |
The fully-qualified class name of the Throwable |
errorMessage |
String |
The message string from the Throwable |
stacktrace |
List<Stackframe> |
A representation of the stacktrace |
type |
Error.Type |
The type of error based on the originating platform |
event.getErrors().get(0).setErrorClass("MyError");
event.errors[0].errorClass = "MyError"
bugsnag_error_set_error_class(event, "MyError");
In an Error
object, the stacktrace
is a list of the following Stackframe
objects:
property | type | description |
---|---|---|
file |
String |
The location of the source file |
inProject |
Boolean |
Whether the package is considered to be in your project for the purposes of grouping and readability on the BugSnag dashboard. Project package names can be set in Configuration. |
lineNumber |
Number |
The line number within the source file this stackframe refers to |
method |
String |
The name of the method that was being executed |
It is therefore possible to modify the stacktrace that is associated with the Event
object in the following way:
for (Stackframe frame : event.getErrors().get(0).getStacktrace()) {
// Your code here: e.g. frame.setInProject(true)
}
for (frame in event.errors[0].stacktrace) {
// Your code here: e.g. frame.inProject = true
}
for (int i = 0; i < bugsnag_event_get_stacktrace_size(event); i++) {
bugsnag_stackframe *frame = bugsnag_event_get_stackframe(event, i);
// Your code here: e.g. frame->line_number -= 1;
}
getFeatureFlags
Returns a list of feature flags active at the time of the event.
List<FeatureFlag> features = event.getFeatureFlags();
val features = event.getFeatureFlags()
// There is no equivalent operation in C/C++
For more information, see Feature flags & experiments.
getMetadata
Returns a map of data in the specified section and optionally key:
Map<String, Object> metadata = event.getMetadata("account");
// or
String accountName = (String) event.getMetadata("account", "name");
val metadata = event.getMetadata("account")
// or
val accountName: String? = event.getMetadata("account", "name") as? String
char *account_name = bugsnag_event_get_metadata_string(event, "account", "name");
getUser
Returns the current user information.
String userId = event.getUser().getId();
String userEmail = event.getUser().getEmail();
String userName = event.getUser().getName();
val userId = event.getUser().id
val userEmail = event.getUser().email
val userName = event.getUser().name
char *userId = bugsnag_event_get_user(event).id;
char *userEmail = bugsnag_event_get_user(event).email;
char *userName = bugsnag_event_get_user(event).name;
groupingHash
The grouping hash of the event to override the default grouping on the dashboard. All events with the same grouping hash will be grouped together into one error. This is an advanced usage of the library and mis-using it will cause your events not to group properly in your dashboard.
As the name implies, this option accepts a hash of sorts.
// ... generate the hash
String groupingHash = "f8803769f3e293dfcabdb6dec5100b8c52c6ae6b";
event.setGroupingHash(groupingHash);
// ... generate the hash
val groupingHash = "f8803769f3e293dfcabdb6dec5100b8c52c6ae6b"
event.groupingHash = groupingHash
// ... generate the hash
char *groupingHash = "f8803769f3e293dfcabdb6dec5100b8c52c6ae6b";
bugsnag_event_set_grouping_hash(event, groupingHash);
isUnhandled
By default this is true
if the event was automatically detected by BugSnag and false
if it was reported manually via Bugsnag.notify
. See our product pages for more information on handled vs unhandled events.
event.setUnhandled(false);
event.isUnhandled = false
bugsnag_event_set_unhandled(event, false);
Changing the unhandled
flag for an event will affect how it contributes to your application’s stability score.
originalError
The Throwable object that caused the event in your application.
Manipulating event.originalError
does not affect the error information reported to the BugSnag dashboard. Use event.errors
to access and amend the representation of the error that will be sent.
if (event.getOriginalError() instanceof CustomApplicationException) // ...
if (event.originalError is CustomApplicationException) // ...
// There is no equivalent operation in C/C++
setUser
Sets the current user information.
event.setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag");
event.setUser("3", "bugs.nag@bugsnag.com", "Bugs Nag")
bugsnag_event_set_user(event, "3", "bugs.nag@bugsnag.com", "Bugs Nag");
null
can be used as a parameter value to clear the user attribute.
severity
The severity of the event. By default, unhandled exceptions will be Severity.ERROR
and handled exceptions sent with Bugsnag.notify
will be Severity.WARNING
.
event.setSeverity(Severity.WARNING);
event.severity = Severity.WARNING
bugsnag_event_set_severity(event, BSG_SEVERITY_ERR);
threads
If thread state is being captured along with the event, event.threads
will contain a list of Thread
objects as follows:
property | type | description |
---|---|---|
id |
String |
The unique ID of the thread (from java.lang.Thread ) |
isErrorReportingThread |
Boolean |
Whether the thread was the thread that caused the event |
name |
String |
The name of the thread (from java.lang.Thread ) |
stacktrace |
List<Stackframe> |
A representation of the stacktrace when the event occurred |
state |
Thread.State |
The state of the thread when the event occurred |
type |
ErrorType |
The type of thread based on the originating platform |
event.getThreads().get(0).setName("New name");
event.threads[0].name = "New name"
// There is no equivalent operation in C/C++
id
and type
changed types in v6.x of the SDK. In v5 they were int
and ThreadType
respectively.