ACRA and Logentries
Posted by Guillaume at November 1, 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
- You know how to use ACRA (Documentation)
- You have a Logentries account and an user key (Step by Step guide)
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.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)
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.
