If you're using Google Analytics to capture crashes in your application you may have noticed that uncaught exceptions give you very little information (just the exception message):
Google Analytics documentation does mention that you can use your own custom ExceptionReporter / ExceptionParser. Decompiling the library though you can see how it is all implemented - I should note that this article is based on Google Analytics v2.0 b4 and may or may not work with other versions.
Instead of creating a new ExceptionReporter and attaching it as a default handler, will assign a custom ExceptionParser in the default ExceptionReporter. That is mainly because from looking at the code the suggested way will chain handlers, possibly producing duplicate reports.
The replacement will go the Application class, before anything else (you could do it if you want in any other activity, although once is enough). First EasyTracker.getInstance().setContext() call initializes the structures, calling EasyTracker.loadParameters() method - among other things it will also create an ExceptionParser and set it as a default exception handler - Thread.setDefaultUncaughtExceptionHandler(). Should note that the uncaught exception handler is only set when you have set a ga_trackingId and ga_reportUncaughtExceptions = true in your analytics.xml config file.
My custom AnalyticsExceptionParser uses Apache Commons Lang ExceptionUtils, but just as well you could use your own implementation.
An error occured while executing doInBackground()
Google Analytics documentation does mention that you can use your own custom ExceptionReporter / ExceptionParser. Decompiling the library though you can see how it is all implemented - I should note that this article is based on Google Analytics v2.0 b4 and may or may not work with other versions.
Instead of creating a new ExceptionReporter and attaching it as a default handler, will assign a custom ExceptionParser in the default ExceptionReporter. That is mainly because from looking at the code the suggested way will chain handlers, possibly producing duplicate reports.
The replacement will go the Application class, before anything else (you could do it if you want in any other activity, although once is enough). First EasyTracker.getInstance().setContext() call initializes the structures, calling EasyTracker.loadParameters() method - among other things it will also create an ExceptionParser and set it as a default exception handler - Thread.setDefaultUncaughtExceptionHandler(). Should note that the uncaught exception handler is only set when you have set a ga_trackingId and ga_reportUncaughtExceptions = true in your analytics.xml config file.
package com.your.package;
import com.google.analytics.tracking.android.EasyTracker;
import com.google.analytics.tracking.android.ExceptionReporter;
public class Application extends android.app.Application {
/*
* (non-Javadoc)
* @see android.app.Application#onCreate()
*/
public void onCreate() {
[...]
/*
* Google Analytics...
*/
EasyTracker.getInstance().setContext(this);
// Change uncaught exception parser...
// Note: Checking uncaughtExceptionHandler type can be useful if clearing ga_trackingId during development to disable analytics - avoid NullPointerException.
Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
if (uncaughtExceptionHandler instanceof ExceptionReporter) {
ExceptionReporter exceptionReporter = (ExceptionReporter) uncaughtExceptionHandler;
exceptionReporter.setExceptionParser(new AnalyticsExceptionParser());
}
}
}
My custom AnalyticsExceptionParser uses Apache Commons Lang ExceptionUtils, but just as well you could use your own implementation.
package com.your.package.util;
import org.apache.commons.lang3.exception.ExceptionUtils;
import com.google.analytics.tracking.android.ExceptionParser;
public class AnalyticsExceptionParser implements ExceptionParser {
/*
* (non-Javadoc)
* @see com.google.analytics.tracking.android.ExceptionParser#getDescription(java.lang.String, java.lang.Throwable)
*/
public String getDescription(String p_thread, Throwable p_throwable) {
return "Thread: " + p_thread + ", Exception: " + ExceptionUtils.getStackTrace(p_throwable);
}
}Now this will produce you a complete stack trace with class names and line numbers, that should be very helpful to figure out where the problem happened exactly.* * *
You can apply similar to EasyTracker.getTracker() setting your custom ExceptionParser with EasyTracker.getTracker().setExceptionParser(...) for caught exceptions, although not necessary as probably in those cases you will want to send the exception plus some other contextual data to figure out the context, and for what you can use sendException(String description, boolean fatal) e.g.:
String response = null;
try {
[...]
response = doSomething();
}
catch (Throwable t) {
// Analytics...
EasyTracker.getTracker().sendException("response = " + response + ", " + ExceptionUtils.getStackTrace(t), false);
// Logging...
if (BuildConfig.DEBUG) {
Log.e(TAG, ExceptionUtils.getStackTrace(t));
}
}


