Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android Apps
GitHub logo Twitter logo OReilly Book Cover Art
Using a Local Runtime Application Log for Analysis of Field Errors or SituationsBack to Android Cookbook Home | Up to Chapter: Testing

Author: Atul Nene ('atulnene')
In Published Edition? Yes
FormatLanguage: WikiFormat

Using a Local Runtime Application Log for Analysis of Field Errors or Situations


Users reported something about your App that you don't think should happen, but now that the 'release mode' App is on the market, you have no way to find out whats going on in the users environment and bug reports end up in a 'cannot reproduce' scenario.


You need to design a built-in mechanism into your App that will give additional insight in such cases. You know the important events or state changes or the resource needs of your app and if you log them in a run-time application log from your App, then the log becomes an additional much needed resource that goes to the heart of the issue being reported and investigated. This simple preventive measure and mechanism goes a long way in reducing the low user ratings for the App, caused by unforeseen situations, and improves the quality of the overall user experience of the App for all users.

One solution is to use the standard java.util.logging package.


You think you have designed, developed and tested your application and released it on the Android marketplace, and that you can now take a vacation. Not so fast! Apart from the simplistic cases, one cannot take care of all possible scenarios during App testing, not that there is the luxury of time for this, and some unexpected App behavior is bound to be reported by Users some time or the other. It need not necessarily be a bug, it might simply be a run-time situation you haven't encountered in your testing. Prepare for this in advance by designing a runtime application log mechanism into your App.

Log the most important events from your app into the log. For example, a state change, a resource timeout (net access, thread wait), or a maxed out retry count. It might even be worthwhile to defensively log an unexpected code path execution in a strange scenario, or some of the most important notifications that are reached to the user.

Care needs to be taken that these log statements are kept to a minimum necessary number. Else the large size of the log itself may become a problem and, while Log.d() calls are ignored at runtime in signed apps, too many log statements may still slow down the App. Only log the statements that will give insight into how the App is working should be there. Nothing more.

Why won't LogCat and ACRA suffice ?

Here's how the class looks:

// Use these built in mechanisms 
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class RuntimeLog {
  public static final int MODE_DEBUG = 1;
  public static final int MODE_RELEASE = 2;
  public static final int ERROR = 3;
  public static final int WARNING = 4;
  public static final int INFO = 5;
  public static final int DEBUG = 6;
  public static final int VERBOSE = 7;

  // Change this to MODE_DEBUG to use for in-house debugging
  static boolean Mode = MODE_RELEASE;
  static logfileName = "/sdcard/YourAppName.log"
  static Logger logger;
  static LogRecord record;

  //initiate the log on first use of the class and 
  //create your custom formatter 

  static {
    try {
      FileHandler fh = new FileHandler(logfileName, true);
      fh.setFormatter(new Formatter() {
        public String format(LogRecord rec) {
          StringBuffer buf = new StringBuffer(1000);
          buf.append(new java.util.Date().getDate());
          buf.append(new java.util.Date().getMonth());
          buf.append((new java.util.Date().getYear())%100);
          buf.append(' ');
          buf.append(new java.util.Date().getHours());
          buf.append(new java.util.Date().getMinutes());
          buf.append(new java.util.Date().getSeconds());
          return buf.toString();
      logger = Logger.getLogger(logfileName);
    catch (IOException e) {

  // the log method
  public static void log(int logLevel,String msg) {
    //don't log DEBUG and VERBOSE statements in release mode 
    if (Mode == MODE_RELEASE) && (logLevel >= DEBUG))
    record=new LogRecord(Level.ALL, msg);
    try {
      switch(logLevel) {
        case ERROR: 
        case WARNING:
        case INFO:
        //FINE and FINEST levels may not work on some API versions
        //use INFO instead
        case DEBUG:
        case VERBOSE:
    catch(Exception exception) {

Additional Possibilities

Usage is simple

RuntimeLog.log (RuntimeLog.ERROR, "Network resource access request failed");
RuntimeLog.log (RuntimeLog.WARNING, "App changed state to STRANGE_STATE");

and so on.

Whenever needed, you can always ask for user co-operation to retrieve the log file(s) from SDCARD and send them to your support team. Even better, you could write code to do that at the press of a button!

More things to consider


Designing this preventive, local, run-time log mechanism into your App will leave that window of opportunity open for getting insight into unforeseen run-time issues that your user runs into with your App.

See Also

ACRA [1]. Getting Bug Reports from Users Automatically with BugSense. Debugging using Log.d and LogCat.