/backtrace-android

Error reporting for Android-based devices

Primary LanguageJavaMIT LicenseMIT

Backtrace

Maven Central Build Status

Backtrace's integration with Android applications written in Java or Kotlin which allows customers to capture and report handled and unhandled java exceptions to their Backtrace instance, instantly offering the ability to prioritize and debug software errors.

Usage

Java

// replace with your endpoint url and token
BacktraceCredentials credentials = new BacktraceCredentials("<endpoint-url>", "<token>");
BacktraceClient backtraceClient = new BacktraceClient(getApplicationContext(), credentials);

try {
    // throw exception here
} catch (Exception exception) {
    backtraceClient.send(new BacktraceReport(e));
}

Kotlin

// replace with your endpoint url and token
val backtraceCredentials = BacktraceCredentials("<endpoint-url>", "<token>")
val backtraceClient = BacktraceClient(applicationContext, backtraceCredentials)

try {
    // throw exception here
}
catch (e: Exception) {
    backtraceClient.send(BacktraceReport(e))
}

Table of contents

  1. Features Summary
  2. Supported SDKs
  3. Differences and limitations of the SDKs version
  4. Installation
  5. Running sample application
  6. Using Backtrace library
  7. Documentation

Features Summary

  • Light-weight Java client library that quickly submits exceptions and crashes to your Backtrace dashboard. Can include callstack, system metadata, custom metadata and file attachments if needed.
  • Supports a wide range of Android SDKs.
  • Supports offline database for error report storage and re-submission in case of network outage.
  • Fully customizable and extendable event handlers and base classes for custom implementations.
  • Supports detection of blocking the application's main thread (Application Not Responding).
  • Supports monitoring the blocking of manually created threads by providing watchdog.

Supported SDKs

  • Minimal SDK version 19 (Android 4.4)
  • Target SDK version 28 (Android 9.0)

Differences and limitations of the SDKs version

  • Getting the status that the device is in power saving mode is available from API 21.

Installation

Download library via Gradle or Maven

  • Gradle
dependencies {
    implementation 'com.github.backtrace-labs.backtrace-android:backtrace-library:3.0.2'
}
  • Maven
<dependency>
  <groupId>com.github.backtrace-labs.backtrace-android</groupId>
  <artifactId>backtrace-library</artifactId>
  <version>3.0.2</version>
  <type>aar</type>
</dependency>

Permissions

Internet permission

  • To send errors to the server instance you need to add permissions for Internet connection into AndroidManifest.xml file in your application.
<uses-permission android:name="android.permission.INTERNET" />

File access

  • To send file attachments from external storage to the server instance you need to add permissions for read external storage into AndroidManifest.xml file in your application.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Running sample application

Android Studio

  • Open MainActivity.java class in app\src\main\java\backtraceio\backtraceio and replace BacktraceCredential constructor parameters with your Backtrace endpoint URL (e.g. https://xxx.sp.backtrace.io:6098) and submission token:

Java

BacktraceCredentials credentials = new BacktraceCredentials("https://<yourInstance>.sp.backtrace.io:6098/", "<submissionToken>");

Kotlin

val backtraceCredentials = BacktraceCredentials("https://<yourInstance>.sp.backtrace.io:6098/", "<submissionToken>")

First start:

  • Press Run and Run.. or type keys combination Alt+Shift+F10.
  • As module select app other options leave default.
  • Select Run and then select your emulator or connected device.
  • You should see new errors in your Backtrace instance. Refresh the Project page or Query Builder to see new details in real-time.

Using Backtrace library

Initialize a new BacktraceClient

First create a BacktraceCredential instance with your Backtrace endpoint URL (e.g. https://xxx.sp.backtrace.io:6098) and submission token, and supply it as a parameter in the BacktraceClient constructor:

Java

BacktraceCredentials credentials = new BacktraceCredentials("https://<yourInstance>.sp.backtrace.io:6098/", "<submissionToken>");
BacktraceClient backtraceClient = new BacktraceClient(getApplicationContext(), credentials);

Kotlin

val backtraceCredentials = BacktraceCredentials("https://<yourInstance>.sp.backtrace.io:6098/", "<submissionToken>")
val backtraceClient = BacktraceClient(applicationContext, backtraceCredentials)

Another option for creating a BacktraceCredentials object is using the URL to which the report is to be sent, pass URL string as parameter to BacktraceCredentials constructor:

Java

BacktraceCredentials credentials = new BacktraceCredentials("https://submit.backtrace.io/{universe}/{token}/json");

Kotlin

val backtraceCredentials = BacktraceCredentials("https://submit.backtrace.io/{universe}/{token}/json")

Setting global custom attributes

It is possible to add your global custom attributes to BacktraceClient and send them with each of report. To do it you should pass map with custom attributes to BacktraceClient constructor method.

Java

Map<String, Object> attributes = new HashMap<String, Object>(){{
    put("custom-attribute-key", "custom-attribute-value");
}};
BacktraceClient backtraceClient = new BacktraceClient(context, credentials, attributes);

Kotlin

val attributes: HashMap<String, Any> = hashMapOf("custom-attribute-key" to "custom-attribute-value")
val backtraceClient = BacktraceClient(context, credentials, attributes)

Enabling ANR detection

Backtrace client allows you to detect that main thread is blocked, you can pass timeout as argument and event which should be executed instead of sending the error information to the Backtrace console by default. You can also provide information that the application is working in the debug mode by providing debug parameter, then if the debugger is connected errors will not be reported. Default value of timeout is 5 seconds.

backtraceClient.enableAnr(timeout, event, debug);

Database initialization

BacktraceClient allows you to customize the initialization of BacktraceDatabase for local storage of error reports by supplying a BacktraceDatabaseSettings parameter, as follows:

Java

BacktraceCredentials credentials = new BacktraceCredentials("https://myserver.sp.backtrace.io:6097/", "4dca18e8769d0f5d10db0d1b665e64b3d716f76bf182fbcdad5d1d8070c12db0");

Context context = getApplicationContext();
String dbPath = context.getFilesDir().getAbsolutePath(); // any path, eg. absolute path to the internal storage

BacktraceDatabaseSettings settings = new BacktraceDatabaseSettings(dbPath);
settings.setMaxRecordCount(100);
settings.setMaxDatabaseSize(100);
settings.setRetryBehavior(RetryBehavior.ByInterval);
settings.setAutoSendMode(true);
settings.setRetryOrder(RetryOrder.Queue);

BacktraceDatabase database = new BacktraceDatabase(context, settings);
BacktraceClient backtraceClient = new BacktraceClient(context, credentials, database);

Sending an error report

Method BacktraceClient.send will send an error report to the Backtrace endpoint specified. There send method is overloaded, see examples below:

Using BacktraceReport

The BacktraceReport class represents a single error report. (Optional) You can also submit custom attributes using the attributes parameter.

Java

try {
    // throw exception here
} catch (Exception e) {
    BacktraceReport report = new BacktraceReport(e, 
    new HashMap<String, Object>() {{
        put("key", "value");
    }}, new ArrayList<String>() {{
        add("absoulte_file_path_1");
        add("absoulte_file_path_2");
    }});
    backtraceClient.send(report);
}

Kotlin

try {
    // throw exception here
}
catch (e: Exception) {
    val report = BacktraceReport(e, mapOf("key" to "value"), listOf("absolute_file_path_1", "absolute_file_path_2"))
    backtraceClient.send(report)
}

Asynchronous Send support

Method send behind the mask use dedicated thread which sending report to server. You can specify the method that should be performed after completion.

Java

client.send(report, new OnServerResponseEventListener() {
    @Override
    public void onEvent(BacktraceResult backtraceResult) {
        // process result here
    }
});

Kotlin

client.send(report) { backtraceResult ->
    // process result here
}

Other BacktraceReport overloads

BacktraceClient can also automatically create BacktraceReport given an exception or a custom message using the following overloads of the BacktraceClient.send method:

Java

try {
  // throw exception here
} catch (Exception exception) {

  backtraceClient.send(new BacktraceReport(exception));
  
  // pass exception to send method
  backtraceClient.send(exception);
  
  // pass your custom message to send method
  backtraceClient.send("Message");
}

Kotlin

try {
    // throw exception here
} catch (exception: Exception) {
  backtraceClient.send(BacktraceReport(exception));
  
  // pass exception to send method
  backtraceClient.send(exception);
  
  // pass your custom message to send method
  backtraceClient.send("Message");
}

Attaching custom event handlers

All events are written in listener pattern. BacktraceClient allows you to attach your custom event handlers. For example, you can trigger actions before the send method:

Java

backtraceClient.setOnBeforeSendEventListener(new OnBeforeSendEventListener() {
    @Override
    public BacktraceData onEvent(BacktraceData data) {
        // another code
        return data;
    }
});

Kotlin

backtraceClient.setOnBeforeSendEventListener { data ->
    // another code
    data
}

BacktraceClient currently supports the following events:

  • BeforeSend
  • RequestHandler
  • OnServerError

Reporting unhandled application exceptions

BacktraceClient also supports reporting of unhandled application exceptions not captured by your try-catch blocks. To enable reporting of unhandled exceptions:

BacktraceExceptionHandler.enable(backtraceClient);

You can add custom map of attributes to BacktraceExceptionHandler which will be sent with each unhandled exception:

BacktraceExceptionHandler.setCustomAttributes(customAttributes);

Enable library logger - debug mode

BacktraceLogger is a class which helps with debugging and analysis code flow execution inside the library. Logger is a wrapper on Android Log class. BacktraceLogger supports 4 logging levels:

  • DEBUG
  • WARN
  • ERROR
  • OFF

In order to enable displaying logs from inside the library, one should set the level from which information should be logged:

BacktraceLogger.setLevel(LogLevel.DEBUG);

Custom client and report classes

You can extend BacktraceBase to create your own Backtrace client and error report implementation. You can refer to BacktraceClient for implementation inspirations.

Monitoring custom threads

Library provides structures and methods to monitor the blocking of your own threads. It is the responsibility of the library user to check whether the thread is blocked and the user's thread should increment the counter.

Java

BacktraceWatchdog watchdog = BacktraceWatchdog(backtraceClient); // Initialize BacktraceWatchdog
watchdog.registerThread(customThread, timeout, delay); // Register custom thread

watchdog.checkIsAnyThreadIsBlocked(); // check if any thread has exceeded the time, by default an error will be sent to the Backtrace console


// The following code should be executed inside the thread you want to monitor
watchdog.tick(this); // In your custom thread class make incrementation to inform that the thread is not blocked

Documentation

BacktraceReport

BacktraceReport is a class that describe a single error report.

BacktraceClient

BacktraceClient is a class that allows you to instantiate a client instance that interacts with BacktraceApi. This class sets up connection to the Backtrace endpoint and manages error reporting behavior. BacktraceClient extends BacktraceBase class.

BacktraceData

BacktraceData is a serializable class that holds the data to create a diagnostic JSON to be sent to the Backtrace endpoint via BacktraceApi. You can add additional pre-processors for BacktraceData by attaching an event handler to the BacktraceClient.setOnBeforeSendEventListener(event) event. BacktraceData require BacktraceReport and BacktraceClient client attributes.

BacktraceApi

BacktraceApi is a class that sends diagnostic JSON to the Backtrace endpoint. BacktraceApi is instantiated when the BacktraceClient constructor is called. You use the following event handlers in BacktraceApi to customize how you want to handle JSON data:

  • RequestHandler - attach an event handler to this event to override the default BacktraceApi.send method.
  • OnServerError - attach an event handler to be invoked when the server returns with a 400 bad request, 401 unauthorized or other HTTP error codes.

BacktraceResult

BacktraceResult is a class that holds response and result from a send method call. The class contains a status property that indicates whether the call was completed (OK), the call returned with an error (ServerError), . Additionally, the class has a message property that contains details about the status.

BacktraceDatabase

BacktraceDatabase is a class that stores error report data in your local hard drive. If DatabaseSettings dones't contain a valid DatabasePath then BacktraceDatabase won't store error report data.

BacktraceDatabase stores error reports that were not sent successfully due to network outage or server unavailability. BacktraceDatabase periodically tries to resend reports cached in the database. In BacktraceDatabaseSettings you can set the maximum number of entries (MaxRecordCount) to be stored in the database. The database will retry sending stored reports every RetryInterval seconds up to RetryLimit times, both customizable in the BacktraceDatabaseSettings.

BacktraceDatabaseSettings has the following properties:

  • DatabasePath - the local directory path where BacktraceDatabase stores error report data when reports fail to send
  • MaxRecordCount - Maximum number of stored reports in Database. If value is equal to 0, then there is no limit.
  • MaxDatabaseSize - Maximum database size in MB. If value is equal to 0, there is no limit.
  • AutoSendMode - if the value is true, BacktraceDatabase will automatically try to resend stored reports. Default is false.
  • RetryBehavior -
    • RetryBehavior.ByInterval - Default. BacktraceDatabase will try to resend the reports every time interval specified by RetryInterval.
    • RetryBehavior.NoRetry - Will not attempt to resend reports
  • RetryInterval - the time interval between retries, in seconds.
  • RetryLimit - the maximum number of times BacktraceDatabase will attempt to resend error report before removing it from the database.

If you want to clear your database or remove all reports after send method you can use clear or flush methods.