Believe it or not, developers are not perfect, and every once in a while you might have a (gasp!) bug in your app.
You will try your best to ship your apps with no bugs in them, but more often than not you realise afterwards that a bug has slipped through the net. Sometimes such bugs result in crashes, which no user likes to encounter.
Never fear though, for there are many excellent iOS crash reporting tools to help you out! They can detect crashes and log details so you can investigate later, and even send you an email summary of when crashes occur and how often.
However, you may wonder which of these tools is the best? Read on to find out!
You’ve spent months working on your newest application, you’ve spent weeks beta testing it, you’ve published it on the App Store, and the positive reviews are starting to roll in. Everything looks great!
But then one user posts a one-star review noting the worst thing possible — the app crashed. Yikes! Nothing is worse than hearing about crashes from the user community.
Although it’s nearly impossible to test for every possible scenario, you can make the triage and troubleshooting portion of your job a little easier by using crash reporting tools in your apps. In fact, they are possibly the most important tool you can make use of to improve your application. Even if you test it thoroughly before the submission to the store, chances are you may have forgotten to check a particular sequence or scenario which leads to a crash.
From a user perspective, a crash is more than just an annoyance. When the application just stops working without any feedback, this often results in lost data and unhappy users. Installing a crash reporting system in your app allows you to obtain all the information you need to be able to fix these annoyances.
When it comes to troubleshooting, the more information that is collected — such as the OS version, the device type, and the application version — the more details you have to track down the source of the bug and fix it. That way, you can turn each crash incident into an opportunity to improve your app!
In this two-part series, you’ll get an overview of the different options of crash reporting tools available to developers. You’ll learn about various free and commercial tools, as well as the various pros and cons of each tool. By the end of the first part, you’ll be able to make an informed choice as to the best tool for your needs. In the second part, you will learn how to get started with each crash reporting service and tie it into your app.
Sound good? Then let’s take a behind-the-scenes look at what goes into a crash reporting tool.
Crash Reporting Basics
A crash reporting tool is actually a combination of two components: a reporting library and a server-side collector. You can think of these items in terms of a restaurant: the reporting library is the kitchen and the collector is the waiter. The developer — i.e. you — plays the part the customer.
You can have the best organized kitchen in the world, but you’ll never eat anything if there isn’t a waiter to bring food to the table. Likewise, your waiter can provide excellent service, but if the food is not well prepared, your experience will not be a good one!
As a great restaurant should include a great kitchen and great waiters, a crash reporting tool should include a great reporting library and a great server-side collector. The role of the reporting library is to prepare the details about a crash. The role of the server-side component is to collect the crash data and present it in a meaningful way.
In iOS crash reporting, there’s one more thing that’s crucial to understanding your crash reports – symbolication. But what is symbolication? You can think of symbolication as the chef in the kitchen, who transforms raw ingredients like bananas, ice cream and rum into something meaningful and tasty such as Bananas Foster.
A crash report contains a stack trace of every thread that was running when the application terminated. This trace is similar to the traces you see in the debugger when paused, although a debugger’s trace will include both instance names and methods (often referred as symbols). In comparison, when an app is built for release, usually these symbol names are stripped from the binary. This means that crash reports coming into your crash reporter service contain strange looking hexadecimal addresses instead of symbol names.
You will no doubt have at least one crash log on your device, so to see what these hexadecimal addresses look like, find such a log like this:
- Connect your device to your Mac.
- Start Xcode and open the Organizer (CMD+Shift+2).
- Find your device on the left and select the “Device Logs” item as shown in the screenshot below:
A list of crash reports will show up, unless your device is brand new and you haven’t used it much. Select one application, and have a look to the right. You should see text displayed similar to the following:
Notice how there are some symbols, for example
-[__NSArrayI objectAtIndex:], and some hexadecimal addresses, for example
0x000db142 0xb1000 + 172354. This is what is known as a partially symbolicated crash log. The top of the stack trace is where the crash occurred, and going down the list indicates which other methods were called to get to where the crash occurred.
The reason that it’s a “partly” symbolicated log is because Xcode is able to symbolicate just the system components like UIKit and CoreFoundation (lines 6 to 18 in the screenshot above). But crashes aren’t usually generated by system libraries, instead they have their roots in the code you write. For example, line 2 indicates that the code path that lead to the crash went through the
objectAtIndex: method on
However, take a look at line 3 in the screenshot above. What’s the meaning of this?
0x000db142 0xb1000 + 172354
This is an example of an un-symbolicated portion of the log. All this tells us is that the crash occurred at the instruction at memory address
0x000db142 which is equal to
0xb1000 + 172354. The reason for it telling us that seemingly obscure bit of math is that
0xb1000 is the start address of the main portion of the app. The 172354 is the important bit as it is the offset into the app.
Note: All these numbers relate to byte offsets within the memory addressable to the CPU. When an application is run, the binary is loaded into memory and read instruction by instruction, by the CPU. The offset where the program is loaded, in this case 0xb1000, is randomised as a minimal form of security against exploits.
But, that’s not terribly useful for debugging purposes. A raw crash report contains what you need to understand the cause of the crash, but you can’t fully comprehend it unless you dive a little deeper and match it up with the source code through a process known as “symbolication”. This is the process of turning these raw numbers into symbols and even pinpointing the exact line of code.