This is a personal blog. The opinions expressed here represent my own and not those of my employer.

ACRA and Logentries

Tue 01 November 2011

If you are an Android developer you probably experiment the annoying situation to debug an issue without any stack trace or detailed information. Hopefully ACRA and Logentries exist. The first one helps you to collect useful data when your application crashes. The second one allows you to store and analyze logs.

The little code below aims at integrate those 2 tools and speed up your debugging process!

Prerequisite

Let's do it

Since ACRA 4 you can make your own ReportSender to send the log collected where you want, and how you want.

public class LogentriesSender implements ReportSender {

    private final AndroidLogger logger;

    private static final String NEW_LINE = System.getProperty("line.separator");
    public static final String LOG_LEVEL_KEY = "LOGLEVEL";

    public LogentriesSender(Context appContext, String userKey,
            String hostname, String logname, boolean immediateUpload) {
        logger = AndroidLogger
                .getLogger(appContext, userKey, hostname, logname);
        logger.setImmediateUpload(immediateUpload);
    }

    public LogentriesSender(Context appContext, String userKey,
            String hostname, String logname) {
        this(appContext, userKey, hostname, logname, true);
    }

    @Override
    public void send(CrashReportData report) throws ReportSenderException {
        int logLevel = Log.ERROR;
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<ReportField, String> reportField : report.entrySet()) {
            String key = reportField.getKey().name();
            if (key.equals(LOG_LEVEL_KEY)) {
                try {
                    logLevel = Integer.parseInt(reportField.getValue());
                } catch (Exception e) {
                    Log.e("LOGGER","failed to parse log level", e);
                }
            } else {
                sb.append(key);
                sb.append("=");
                sb.append(reportField.getValue());
                sb.append(NEW_LINE);
            }
        }

        switch (logLevel) {

        case Log.DEBUG:
            logger.debug(sb.toString());
            break;

        case Log.ERROR:
            logger.error(sb.toString());
            break;

        case Log.VERBOSE:
            logger.verbose(sb.toString());
            break;

        case Log.INFO:
            logger.info(sb.toString());
            break;

        case Log.WARN:
            logger.warn(sb.toString());
            break;

        default:
            logger.verbose(sb.toString());
            break;
        }

    }
}

You need to configure ACRA to use the ReportSender above. For that your custom Application class should look like this:

@ReportsCrashes(forceCloseDialogAfterToast = false, customReportContent = {
        ReportField.APP_VERSION_CODE, ReportField.ANDROID_VERSION,
        ReportField.PHONE_MODEL, ReportField.CUSTOM_DATA,
        ReportField.STACK_TRACE }, mode = ReportingInteractionMode.TOAST, resToastText = R.string.crash_toast_text, formKey = "")
public class MyApplication extends android.app.Application {

    @Override
    public void onCreate() {
        ACRA.init(this);

        LogentriesSender sender = new LogentriesSender(getApplicationContext(),
                "REPLACE_WITH_YOUR_KEY", "myappname",
                "myandroidlogname");
        ErrorReporter.getInstance().setReportSender(sender);

        super.onCreate();
    }
}

AndroidManifest.xml

If you have just created "MyApplication" class don't forget to update your AndroidManifest.xml to use your custom implementation.

<application android:name=".MyApplication" android:icon="@drawable/icon" android:label="@string/app_name"></application>

How using it?

As logentries allows the usage of log level (WARN, ERROR, INFO, etc).

The log level is defined as follow:

  • An unexpected exception will be forwarded to logentries as an ERRROR. (you have nothing to do)
  • When you decide to send by yourself an exception you can choose the log level to apply (see code below)

Example:

ErrorReporter reporter = ErrorReporter.getInstance();
reporter.putCustomData(LogentriesSender.LOG_LEVEL_KEY, Integer.toString(android.util.Log.INFO));
reporter.handleException(new Exception("my exception"));

Source code

The code above with the logentries API have been packaged into an android library. Please note in the previous package the AndroidLogger class has been updated to run in its own thread to avoid any UI slowness when the network connection is poor. The original version can be found on Github.

Something unclear? bug? let me know with a comment.

Comments


Last Articles


Involved in



Guillaume Vaudaux-Ruth