7

I have a project that uses Fabric/crashlytics. In order to be able to detect all runtime errors in production, I want to send (non-fatal) exceptions to Crashlytics using:

Crashlytics.logException(new RuntimeException("some identifiable error message");

I want to add this logic to our existing Log-class in the project that is loaded via gradle as a separate "utilities-module". Since this module doesn't hold a reference to Crashlytics (and I can't seem to find a good way of forwarding this reference from the main module), I have solved it by introducing an interface, implemented from the main application:

if (!BuildConfig.APP_BUILD_VERSION.equals("local")) {
        UtilitiesConfig.setExternalLogger(new Logger.ExternalLogger() {
            @Override
            public void reportError(String tag, String message, Throwable throwable) {
                Crashlytics.logException(new RuntimeException(TextUtils.isEmpty(tag) ? message : tag + ": " + message));
            }
        });
    }

This works fine, only problem is that all reports in Fabric are being grouped as one similar exception, since the top rows of the stack trace are similar (i.e. the interface and the application). For example:

Non-fatal Exception: java.lang.RuntimeException: c: onNetworkError, type: CANT_ACCESS_SERVER
   at my.package.Application$3.reportError(Application.java:234)
   at my.package.utilities.Logger.e(Logger.java:34)
   at my.package.utilities.net.CallbackCallable.onNetworkError(CallbackCallable.java:76)
   at my.package.utilities.net.MsgCallable.onNetworkError(MsgCallable.java:250)
   at my.package.utilities.net.CancellableCallable.call(CancellableCallable.java:80)
   at java.util.concurrent.FutureTask.run(FutureTask.java:237)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
   at java.lang.Thread.run(Thread.java:776)

...and this:

Non-fatal Exception: java.lang.RuntimeException: u: Cannot update
   at my.package.Application$3.reportError(Application.java:234)
   at my.package.utilities.Logger.e(Logger.java:43)
   at my.package.NTPManager$SyncTimeAsyncTask.doInBackground(NTPManager.java:150)
   at my.package.NTPManager$SyncTimeAsyncTask.doInBackground(NTPManager.java:133)
   at android.os.AsyncTask$2.call(AsyncTask.java:304)
   at java.util.concurrent.FutureTask.run(FutureTask.java:237)
   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
   at java.lang.Thread.run(Thread.java:762)

are both being grouped together, despite them being two different errors originating from different classes/rows and with different error messages.

Is there an efficient way of changing either some configuration in Crashlytics or by reporting it through said callback in another fashion, making Fabric not considering them the same error?

Halvtysk
  • 257
  • 2
  • 10
  • 3
    We do not have a supported way of manually breaking grouping in the UI or SDK. I'll let the team know you are interested. – Todd Burner Feb 22 '18 at 22:14

1 Answers1

1

Since issues are grouped by the root cause of the exception, if you used the throwable passed to reportError and set it as the cause of the exception you create, you should get the desired result.

if (!BuildConfig.APP_BUILD_VERSION.equals("local")) {
    UtilitiesConfig.setExternalLogger(new Logger.ExternalLogger() {
        @Override
        public void reportError(String tag, String message, Throwable throwable) {
            String logMessage = TextUtils.isEmpty(tag) ? message : tag + ": " + message;
            Crashlytics.logException(new RuntimeException(logMessage, throwable));
        }
    });
}
arekolek
  • 9,128
  • 3
  • 58
  • 79
  • Great, it seemed that since I posted the question we passed the throwable in some cases, and these (just like you described) are reported separately. I wouldn't have figured out the connection if you hadn't told me. :) – Halvtysk Jan 31 '20 at 10:23
  • 1
    Yep, it baffled me too, and took quite a bit of experimentation to figure it out ;) – arekolek Jan 31 '20 at 11:10