Crash Reporting with Sentry - my-swift-lab/firefox-ios GitHub Wiki
If there is anything in this document that is not clear, is incorrect, or that requires more detail, please file a request through a Github or Bugzilla.
Firefox for iOS uses Sentry for crash and exception reporting. This kind of reporting gives Mozilla invaluable insight as to why Firefox for iOS crashes or incorrectly behaves. It is one of the key methods we use to improve the product in terms of stability.
This page explains how Sentry works, how the various parts interact and what kind of data it sends back to Mozilla.
High Level Summary
Sentry is an open source crash reporting and aggregation platform. Both the client SDK, github.com/getsentry/sentry-cocoa, and the server, github.com/getsentry/sentry, are open source.
The server is hosted and maintained by Mozilla. There are no third-parties involved, all crash reports to directly from Firefox for iOS to the Sentry server hosted by Mozilla.
On the client side Sentry is invisible. There are no parts to interact with. It reports crashes and fatal errors back to Mozilla in the background. Sentry is enabled when the Send Anonymous Usage Data switch in the Firefox for iOS settings is enabled by the user. By default this switch is enabled, it is an opt-out mechanism.
On the server side there is a dashboard that the Firefox for iOS team uses to look at incoming crash reports. The dashboard lets us inspect the crash report in detail and for example see where in the application the crash happened, what version of the application was used and what version of iOS was active. Below is an overview of all the attributes that are part of a crash report.
Sentry Reports
A typical Sentry crash report contains three categories of data: device, application, crash.
Device Information
Sentry collects basic information about the device the application is running on. Both static (device type) and dynamic (memory in use, boot time).
model_id: "J82AP",
family: "iOS",
arch: "arm64",
storage_size: 31989477376,
free_memory: 206585856,
memory_size: 2084569088,
boot_time: "2017-07-22T20:24:34Z",
model: "iPad5,4",
usable_memory: 1860943872,
type: "device"
Application Information
Sentry collects basic information about Firefox for iOS. The device_app_hash
is a Sentry generated identifier that allows it to group crash reports for a specific client. This identifier is unique to Sentry and is useless outside of Sentry. It cannot be used to correlate a specific user to a crash. It is also not related to any identifiers that Firefox for iOS uses internally.
executable_path: "/var/containers/Bundle/Application/07A66DB3-33D8-4C98-ABE6-AE3571A0189C/Client.app/Client",
app_identifier: "org.mozilla.ios.Firefox",
device_app_hash: "971aee19c94f2ec9b35518973bd306020745cabb",
build_type: "app store",
app_start_time: "2017-07-25T13:57:23Z",
app_version: "8.0",
type: "app",
app_build: "4558"
Crash Information
Exception message
Every crash report contains a reason - why did this crash happen. This field can contain two different values:
- an error message generated by iOS
- an error message generated by Firefox
Both Apple and Mozilla make sure that no personally identifiable information is put in any of these messages. We keep them technical and to the point.
Example of an iOS generated message:
NSInternalInconsistencyException - fatalApplication threw exception NSInternalInconsistencyException:
attempt to delete item 1 from section 0 which only contains 1 items before the update
Example of a Firefox generated message:
BEGIN EXCLUSIVE failed. Error code: 0, Error Domain=mozilla Code=0 "Non-open connection;
can't execute change." UserInfo={NSLocalizedDescription=Non-open connection; can't execute change.}
Images
Every crash report contains a list of libraries and frameworks that the application links against. These include: Frameworks written by the Firefox for iOS team, Third-Party frameworks that we link against and finally system frameworks.
The UUID
fields in these image descriptions are the same for every copy of Firefox for iOS and are not connected to a specific installation, device or user.
cpu_subtype: 0,
name: "/var/containers/Bundle/Application/07A66DB3-33D8-4C98-ABE6-AE3571A0189C/Client.app/Client",
revision_version: 0,
major_version: 0,
image_vmaddr: "0x100000000",
image_addr: "0x100060000",
minor_version: 0,
cpu_type: 16777228,
image_size: 3571712,
type: "apple",
uuid: "D16EC59F-2361-3621-A62F-AB41F5F0F869"
cpu_subtype: 0,
name: "/System/Library/Frameworks/Accelerate.framework/Frameworks/vImage.framework/vImage",
revision_version: 0,
major_version: 331,
image_vmaddr: "0x1826db000",
image_addr: "0x18f347000",
minor_version: 5,
cpu_type: 16777228,
image_size: 2732032,
type: "apple",
uuid: "1F670947-59DE-3818-9883-0A3692EDFF0F"
Stack trace
Every crash report contains a stack trace, which shows what functions in the Firefox for iOS code led to this crash. It includes names of iOS system functions and Firefox for iOS functions.
0 CoreFoundation 0x30f7ccfe0 __exceptionPreprocess
1 libobjc.A.dylib 0x30cdb4538 objc_exception_throw
2 CoreFoundation 0x30f7cceb4 +[NSException raise:format:arguments:]
3 Foundation 0x310d7a720 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
4 UIKit 0x31c446d24 -[UICollectionView _endItemAnimationsWithInvalidationContext:tentativelyForReordering:animator:]
5 UIKit 0x31bd09f1c -[UICollectionView _updateRowsAtIndexPaths:updateAction:]
6 Client 0x2000c9e9c specialized TopTabsViewController.((reloadData in _3434E9307FC2B0225EF0EAC66FE81010)() -> ()).(closure #1) (TopTabsViewController.swift:454)
7 Client 0x2000c5304 [inlined] TopTabsViewController.((reloadData in _3434E9307FC2B0225EF0EAC66FE81010)() -> ()).(closure #1)
8 Client 0x2000c5304 partial apply for TopTabsViewController.((reloadData in _3434E9307FC2B0225EF0EAC66FE81010)() -> ()).(closure #1)
9 UIKit 0x31bb733dc +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:]
10 UIKit 0x31bcb7a24 +[UIView(UIViewAnimationWithBlocks) animateWithDuration:animations:completion:]
11 Client 0x2000c0150 TopTabsViewController.(reloadData in _3434E9307FC2B0225EF0EAC66FE81010)() -> () (TopTabsViewController.swift:463)
12 Client 0x2000c2e60 [inlined] TopTabsViewController.tabManager(TabManager, didSelectedTabChange : Tab?, previous : Tab?) -> ()
13 Client 0x2000c2e60 @objc TopTabsViewController.tabManager(TabManager, didSelectedTabChange : Tab?, previous : Tab?) -> ()
14 Client 0x2000c3084 [inlined] dynamic TopTabsViewController.tabManager(TabManager, didSelectedTabChange : Tab?, previous : Tab?) -> ()
15 Client 0x2000c3084 protocol witness for TabManagerDelegate.tabManager(TabManager, didSelectedTabChange : Tab?, previous : Tab?) -> () in conformance TopTabsViewController (TopTabsViewController.swift:497)
16 Client 0x20025945c [inlined] specialized TabManager.(selectTab(Tab?, previous : Tab?) -> ()).(closure #1) (TabManager.swift:192)
17 Client 0x20025945c [inlined] TabManager.(selectTab(Tab?, previous : Tab?) -> ()).(closure #1) (TabManager.swift:192)
18 Client 0x20025945c [inlined] thunk
19 Client 0x20025945c [inlined] specialized Sequence.forEach((A.Iterator.Element) throws -> ()) throws -> ()
20 Client 0x20025945c specialized TabManager.selectTab(Tab?, previous : Tab?) -> () (TabManager.swift:192)
21 Client 0x2000c1970 [inlined] TabManager.selectTab(Tab?, previous : Tab?) -> ()
22 Client 0x2000c1970 TopTabsViewController.togglePrivateModeTapped() -> () (TopTabsViewController.swift:215)
23 Client 0x2000c1a40 @objc TopTabsViewController.togglePrivateModeTapped() -> ()
24 UIKit 0x31bb73010 -[UIApplication sendAction:to:from:forEvent:]
25 UIKit 0x31bb72f90 -[UIControl sendAction:to:forEvent:]
26 UIKit 0x31bb5d504 -[UIControl _sendActionsForEvents:withEvent:]
27 UIKit 0x31bb72874 -[UIControl touchesEnded:withEvent:]
28 UIKit 0x31bb72390 -[UIWindow _sendTouchesForEvent:]
29 UIKit 0x31bb6d728 -[UIWindow sendEvent:]
30 UIKit 0x31bb3e33c -[UIApplication sendEvent:]
31 UIKit 0x31c338014 __dispatchPreprocessedEventFromEventQueue
32 UIKit 0x31c332770 __handleEventQueue
33 UIKit 0x31c332b9c __handleHIDEventFetcherDrain
34 CoreFoundation 0x30f77b42c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
35 CoreFoundation 0x30f77ad04 __CFRunLoopDoSources0
36 CoreFoundation 0x30f7789a8 __CFRunLoopRun
37 CoreFoundation 0x30f6a8da4 CFRunLoopRunSpecific
38 GraphicsServices 0x312b78074 GSEventRunModal
39 UIKit 0x31bba3058 UIApplicationMain
40 Client 0x2000695dc main (main.swift:16)
41 libdyld.dylib 0x30d6ca59c start