In order to quickly reproduce and fix errors, it is often helpful to send additional application-specific diagnostic “metadata” 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.
If you’d like to add diagnostic data to reports, or adjust event data conditionally, you can register a block to be run before an error is delivered to your BugSnag dashboard:
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
[config addOnSendErrorBlock:^BOOL (BugsnagEvent *event) {
[event addMetadata:@"Acme Co." withKey:@"name" toSection:@"account"];
[event addMetadata:@(YES) withKey:@"paying_customer" toSection:@"account"];
// Return `NO` if you'd like to stop this error being reported
return YES;
}];
[Bugsnag startWithConfiguration:config];
let config = BugsnagConfiguration.loadConfig()
config.addOnSendError { (event) -> Bool in
event.addMetadata("Acme Co.", key:"name", section:"account")
event.addMetadata(true, key:"paying_customer", section:"account")
// Return `false` if you'd like to stop this error being reported
return true
}
Bugsnag.start(with: config)
The callback gives you access to an event
object, so you can inspect and modify the error event which is about to be sent to BugSnag.
If the app has crashed, these delivery-time callbacks will be executed when the app next launches and has network connectivity. They are invoked on a dedicated background queue, which will be different from the queue where the block was originally added. This means the state of the app and device are likely to be different to how they were when the crash occurred and so care must be taken when reading or adding external data in a callback. See Crash-time handler for information on capturing data during a crash.
If you want to prevent an event from being sent to BugSnag, you can return false within the callback block. This would allow for users to opt out of sending error reports, for example:
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
[config addOnSendErrorBlock:^BOOL (BugsnagEvent *event) {
return ![self userHasOptedOut];
}];
[Bugsnag startWithConfiguration:config];
let config = BugsnagConfiguration.loadConfig()
config.addOnSendError { (event) -> Bool in
return !self.userHasOptedOut()
}
Bugsnag.start(with: config)
When a crash occurs in an application, information about the runtime state of the application is collected and written to a crash file to be sent to BugSnag at the next opportunity. The onCrashHandler
hook allows you to execute additional code during the crash, before the data is written to file.
However because the callback is executing at crash-time, it must be asynchronous-safe. This greatly reduces the functionality that can safely be executed: in particular this means that Objective-C code cannot be used. A C function can be registered as follows:
// Create crash handler
#import <Bugsnag/BSG_KSCrashReportWriter.h>
void HandleCrashedThread(const BSG_KSCrashReportWriter *writer) {
// add metadata
writer->beginObject(writer, "account");
writer->addStringElement(writer, "name", "Acme Co.");
writer->endContainer(writer);
// possibly serialize data, call another crash reporter, ...
}
// Assign crash handler function to the configuration
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
config.onCrashHandler = &HandleCrashedThread;
[Bugsnag startWithConfiguration:config];
// Assign crash handler function to the configuration
let config = BugsnagConfiguration.loadConfig()
config.onCrashHandler = HandleCrashedThread
Bugsnag.start(with: config)
The writer
parameter provided allows you to add data to the crash report file (in JSON format), which will later be sent to your dashboard where your data will appear as metadata in the reported event. The data added to writer
must be a string at the top-level with a dictionary value, which can have an arbitrary structure inside it. In this way, the top-level string will be the section (or tab) in which the data appears in your dashboard. See BSG_KSCrashReportWriter.h
for a list of available operations.
The data is available in the event passed to delivery-time callbacks where it can be queried or amended in a more hospitable environment:
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
[config addOnSendErrorBlock:^BOOL (BugsnagEvent *event) {
NSDictionary *accountData = [event getMetadataFromSection:@"account"];
// Perform actions based on crash-time data
return YES;
}];
[Bugsnag startWithConfiguration:config];
let config = BugsnagConfiguration.loadConfig()
config.addOnSendError { (event) -> Bool in
let accountData = event.getMetadata(section: "account")
// Perform actions based on crash-time data
return true
}
Bugsnag.start(with: config)
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 dictionary:
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
[config addMetadata:@"Acme Co." withKey:@"name" toSection:@"account"];
[config addMetadata:@{ @"delivery": @"express", @"sale": @"spring" }
toSection:@"basket"];
[Bugsnag startWithConfiguration:config];
let config = BugsnagConfiguration.loadConfig()
config.addMetadata("Acme Co.", key: "name", section: "account")
config.addMetadata(["delivery": "express", "sale": "spring"],
section: "basket")
Bugsnag.start(with: config)
Metadata can also be managed whilst your application is running using addMetadata
and clearMetadata
on the Bugsnag
client:
[Bugsnag addMetadata:@"Acme Co." withKey:@"name" toSection:@"account"];
// ...
[Bugsnag clearMetadataFromSection:@"account"];
Bugsnag.addMetadata("Acme Co.", key: "name", section: "account")
// ...
Bugsnag.clearMetadata(section: "account")
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:
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
[config setUser:@"3" withEmail:@"bugs.nag@bugsnag.com" andName:@"Bugs Nag"];
[Bugsnag startWithConfiguration:config];
let config = BugsnagConfiguration.loadConfig()
config.setUser("3", withEmail: "bugs.nag@bugsnag.com", andName: "Bugs Nag")
Bugsnag.start(with: config)
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" withEmail:@"bugs.nag@bugsnag.com" andName:@"Bugs Nag"];
Bugsnag.setUser("3", withEmail: "bugs.nag@bugsnag.com", andName: "Bugs Nag")
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 to the file name and line number of the topmost in-project stackframe. If you would like to set this value manually, you can set it with an initial value in Configuration when BugSnag starts:
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
config.context = @"InitialTutorialStep";
[Bugsnag startWithConfiguration:config];
let config = BugsnagConfiguration.loadConfig()
config.context = "InitialTutorialStep"
Bugsnag.start(with: config)
The context can then be amended on the Bugsnag
client as/when it changes for all subsequent events:
[Bugsnag setContext:@"SecondTutorialStep"];
Bugsnag.setContext("SecondTutorialStep")
Alternatively, the context can be amended for each event using a callback block:
BugsnagConfiguration *config = [BugsnagConfiguration loadConfig];
[config addOnSendErrorBlock:^BOOL (BugsnagEvent *event) {
event.context = @"SecondTutorialStep";
return YES;
}];
[Bugsnag startWithConfiguration:config];
let config = BugsnagConfiguration.loadConfig()
config.addOnSendError { (event) -> Bool in
event.context = "SecondTutorialStep"
return true
}
Bugsnag.start(with: config)
BugsnagEvent
classA BugsnagEvent
object represents an error captured by BugSnag and is available as a parameter on an event callback block. The following properties and methods are available on an Event
for you to query and update the captured data.
addFeatureFlag
Declare a single feature flag or experiment with variant as an optional second parameter.
[event addFeatureFlagWithName:@"Checkout button color" variant:@"Blue"];
[event addFeatureFlagWithName:@"New checkout flow"];
event.addFeatureFlag(name: "Checkout button color", variant: "Blue")
event.addFeatureFlag(name: "New checkout flow")
addFeatureFlags
Declare multiple feature flags or experiments.
[event addFeatureFlags:@[
[BugsnagFeatureFlag flagWithName:@"Checkout button color" variant:@"Blue"],
[BugsnagFeatureFlag flagWithName:@"Special offer" variant:@"Free Coffee"],
[BugsnagFeatureFlag flagWithName:@"New checkout flow"]]];
event.addFeatureFlags([
BugsnagFeatureFlag(name: "Checkout button color", variant: "Blue"),
BugsnagFeatureFlag(name: "Special offer", variant: "Free Coffee"),
BugsnagFeatureFlag(name: "New checkout flow")])
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 dictionary or array:
[event addMetadata:@"Acme Co." withKey:@"name" toSection:@"account"];
[event addMetadata:@(YES) withKey:@"paying_customer" toSection:@"account"];
[event addMetadata:@[@"basic", @"admin"] withKey:@"roles" toSection:@"account"];
event.addMetadata("Acme Co.", key: "name", section: "account")
event.addMetadata(true, key: "name", section: "account")
event.addMetadata(["basic", "admin"], key: "roles", section: "account")
Alternatively a whole dictionary can be added for a section:
[event addMetadata:@{ @"delivery": @"express", @"sale": @"spring" }
toSection:@"basket"];
event.addMetadata(["delivery": "express", "sale": "spring"],
section: "basket")
Metadata set on the event will be combined with global metadata set on the Bugsnag
client, with properties on the Event
taking precedence.
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:
NSString *apiKey = event.apiKey;
var apiKey = event.apiKey
app
Information about your app can be found in the app
object:
property | type | description |
---|---|---|
binaryArch |
String |
The architecture of the running application binary |
bundleVersion |
String |
The bundle version used by the application |
codeBundleId |
String |
The revision ID from the manifest (React Native apps only) |
dsymUuid |
String |
Unique identifier for the debug symbols file corresponding to the application |
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 |
These values can be accessed and amended if necessary:
event.app.bundleVersion = [self getCustomBundleVersion];
event.app.bundleVersion = getCustomBundleVersion()
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.breadcrumbs[0].message = @"Left home screen";
event.breadcrumbs?[0].message = "Left home screen"
clearFeatureFlag
Remove a single feature flag or experiment.
[event clearFeatureFlagWithName:@"Checkout button color"];
event.clearFeatureFlag(name: "Checkout button color")
clearFeatureFlags
Remove all feature flags and experiments.
[event clearFeatureFlags];
event.clearFeatureFlags()
clearMetadata
Removes all the data from the specified section or from a key in the section:
[event clearMetadataFromSection:@"account"];
// or
[event clearMetadataFromSection:@"account" withKey:@"name"];
event.clearMetadata(section: "account")
// or
event.clearMetadata(section: "account", key: "name")
context
The context represents what was happening in your application at the time an error occurs.
event.context = @"SecondTutorialStep";
event.context = "SecondTutorialStep"
See Setting context for more information.
device
Information about the device on which the event occurred can be found in event.device
:
property | type | description |
---|---|---|
freeMemory |
Number |
The number of free bytes of memory available on the device |
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 number of bytes of memory on the device |
These values can be accessed and amended if necessary:
event.device.locale = @"de-DE";
event.device.locale = "de-DE"
device.freeDisk
is now only populated on macOS due to Apple’s restrictions on APIs that could be used for fingerprinting on iOS, tvOS and watchOS.
errors
event.errors
is an array of one or more Error
objects. The first item in the list represents the signal or thrown object. Each subsequent item represents the exception that caused the preceding one.
A reference to the actual error object that caused the event (if applicable) is available through event.originalError
.
An Error
object contains the following information:
property | type | description |
---|---|---|
errorClass |
String |
The class of the error generating the event |
errorMessage |
String |
The message of or reason for the error generating the event |
stacktrace |
List<Stackframe> |
A representation of the stacktrace |
type |
Error.Type |
The type of error based on the originating platform |
event.errors[0].errorClass = @"MyErrorClass";
event.errors[0].errorClass = "MyErrorClass"
In an Error
object, the stacktrace
is a list of the following Stackframe
objects:
property | type | description |
---|---|---|
frameAddress |
String |
The stack frame address |
isLr |
String |
Whether the frame was within the link register |
isPc |
String |
Whether the frame was within the program counter |
machoFile |
String |
The Mach-O file used by the stackframe |
machoLoadAddress |
String |
The load address of the Mach-O file |
machoUuid |
String |
A UUID identifying the Mach-O file used by the stackframe |
machoVmAddress |
String |
The VM address of the Mach-O file |
method |
String |
The name of the method that was being executed |
symbolAddress |
String |
The address of the stackframe symbol |
If you use a wrapper function to send handled events, you can trim the function from the event’s stack trace:
NSMutableArray<BugsnagStackframe *> *frames = event.errors[0].stacktrace.mutableCopy;
[frames removeObjectAtIndex:0];
event.errors[0].stacktrace = frames;
event.errors[0].stacktrace.remove(at: 0)
featureFlags
Returns a list of feature flags active at the time of the event.
NSArray<BugsnagFeatureFlag *> *features = event.featureFlags
var features = = event.featureFlags
For more information, see Feature flags & experiments.
getMetadata
Returns a map of data in the specified section and optionally key:
NSDictionary *metadata = [event getMetadataFromSection:@"account"];
// or
NSString *accountName = [event getMetadataFromSection:@"account" withKey:@"name"];
var metadata = event.getMetadata(section: "account")
// or
var accountName = event.getMetadata(section: "account", key: "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
NSString *groupingHash = @"f8803769f3e293dfcabdb6dec5100b8c52c6ae6b";
event.groupingHash = groupingHash;
// ... generate the hash
var groupingHash = "f8803769f3e293dfcabdb6dec5100b8c52c6ae6b"
event.groupingHash = groupingHash
originalError
The original object that caused the error in your application. This value will only be populated for non-fatal errors which did not terminate the process, and will contain an NSError
or NSException
.
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.originalError != nil) &&
[event.originalError isKindOfClass:NSError.class]) {
if([((NSError *)event.originalError).domain isEqualToString:@"myDomain"]) {
// ...
}
}
if let error = event.originalError as? NSError {
if error.domain == "myDomain" {
// ...
}
}
setUser
Sets the current user information.
[event setUser:@"3" withEmail:@"bugs.nag@bugsnag.com" andName:@"Bugs Nag"];
event.setUser("3", withEmail: "bugs.nag@bugsnag.com", andName: "Bugs Nag")
nil
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.severity = BSGSeverityWarning;
event.severity = .warning
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 |
Number |
A unique ID which identifies this thread |
errorReportingThread |
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 |
Thread.Type |
The type of thread based on the originating platform |
event.threads[0].name = @"New name";
event.threads[0].name = "New name"
unhandled
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.unhandled = YES;
event.unhandled = true
Changing the unhandled
flag for an event will affect how it contributes to your application’s stability score.
user
Returns the current user information.
NSString *userId = event.user.id;
NSString *userEmail = event.user.email;
NSString *userName = event.user.name;
var userId = event.user.id
var userEmail = event.user.email
var userName = event.user.name