Being an app developer I always liked how easy it is to add crash collection to my apps, but after switching to library development I’ve found myself in an opposite situation. How do I track and analyse crashes in my library?
Here at Avo we have a couple of open source libraries for mobile. We have part of one of our main products distributed as a library, the Avo Inspector SDK, and we have our mobile debugger.
At one point we realized that there is a problem, we don’t have access to crash reports from the libraries. When the library is integrated to a third party app and crashes, that crash is collected by the app and it actually crashes the whole app, which is really bad. At the beginning we were in a situation where we relied on the crash information we get from our clients. We also lacked a good tool to organize the reports, something similar to what you get in Crashlytics for example.
Our library, Avo Inspector, monitors tracking and collects metadata about it, it's not the core functionality of the app, so we decided that failure of the library should not be terminal to the app. We will collect the crashes when they happen and let the app do it's main job undistracted.
As with all problems we face in software development, there are multiple possible solutions here with their own drawbacks.
Most companies solve this problem by having their app with a decent amount of users where they use their sdk and monitor crash reports. Unfortunately it's not our case, since our product is a web app and a set of developer tools.
Being a seed stage startup with a very small engineering team and huge list of product opportunities we try to utilise existing software as much as possible and invest as much time as we can in development of our product, so the first thing we did to figure out this problem was to look for a well built existing solution. To our great surprise we have not found any. There are quite a few different crash management tools for apps, but nothing dedicated for libraries.
Technically we can use an app-based solution, but then the dependencies and library initialization may collide if the integrating app uses the same tool for crash reporting internally. Actually duplicate dependencies is not a huge issue and gradle would take care of it for us (read more about how gradle resolves dependencies here) and in the worst case will fail the build, while the initialization is trickier. Most of the libraries do not allow having 2 instances sending crashes to 2 different destinations. Another complication is that those app specific crash reporting tools usually collect a lot of additional app data by default that we don't really want to collect as a library, like sessions or user identifiers.
At that point building our own proxy to collect the crash reports seemed like the only option. We are using Sentry.io in our web app and decided to look into sending crashes there through our own endpoint. But then, when reading the docs, we got another idea. The thing is that alongside an app-specific Android SDK they provide a generic Java SDK that can be used in an Android app.
This Java SDK actually automatically checked out most of our concerns about using a crash reporting SDK in our library.
Chances that there would be a conflict are very low, and for those who use Sentry Java SDK we provide a version of our library without the dependency. The Java SDK is not sending additional app-related information. And integration is just a couple of lines of code. And since we are already using Sentry it was just perfect in our case!
Here is how the code looks in our repo.
The Sentry Java SDK dependency:
One thing we had to do is disable uncaught exception handling. By default Sentry, like most other crash reporting tools, registers a global uncaught exceptions handler that reports errors coming from any part of the application. In case of a library, we don’t want to be notified about exceptions that were thrown outside of our own code, so we disabled the global handler like this:
Then we initialize the library:
And finally we wrapped all public methods in a try-catch and added this handler:
We love this solution for the simplicity and the amount of value we get per unit of effort, it's exactly what we need. You can utilize the same approach, improve the stability and quality of your library and make your clients happier, never worrying about crashes from that 3rd party code they pull in!
In addition to Sentry, https://www.bugsnag.com/, https://raygun.com/ have Java SDKs and can likely be used in the same way. We haven't tried them though, please let us know if you are using one of them in an Android app by sending an email to firstname.lastname@example.org.
Another great option which is more universal is using the new crashes reporting API from AppCenter https://docs.microsoft.com/en-us/appcenter/diagnostics/upload-crashes. It's quite new and was not present when we did initial research.
We have considered using it since then and were quite intrigued, but are still staying with Sentry on Android because of the implementation simplicity and the fact that we are using Sentry for our other products.
In your case utilizing the AppCenter API might be a better option, check it out! Moreover, stay tuned for the news about our iOS crash reporting. They might be posting about AppCenter at some point. 😉