Thursday, May 30, 2013

Saving time while logging on Android, four key strokes at a time

I guess pretty much every Android developer uses logging system, and thus is familiar with the following page from the Android documentation:



That means to log a line you use a call like this:

Log.i(TAG, "Index=" + i);

Where TAG is defined as:

private static final String TAG = "MyActivity";

Proactive developers often don't like the refactoring time bomb of String literal to represent the log tag and often replace it with a following line:

private static final String TAG = MtActivity.class.getSimpleName();

Still this is a lot of code to type, plus the "TAG," parameter every time you use the log command in your code.
Well, you probably don't mind extra four characters typed, but if you multiply this by the number of times you scatter this line in your code (which is quite likely a big, big number), it becomes a large chunk of time that can be better spent doing something else, just because the API asks you to provide the value of the parameter that might be obtained for you automatically.

Let's have a look if there is an alternative. Well, lets just have a similar method, which just omits the TAG parameter. The modified call looks like this:

prn.log("Index=" + i);

Plus we don't have to declare the TAG static variable anymore as well. Sounds like a problem solved. But we still want to have the information in the log file about the location of the log message. Where we get this from ? Will we use the magic ? That's definitely one option, but other one is to leverage the Java Exception system, and do the Stack Trace analysis to obtain the origin of the log message. The scenario is quite simple. First we throw a new Exception and surround it with the catch block that will do the Stack Trace analysis:

What's the catch ? Many of you probably noticed that there is a new object created for every log method call - the new Exception needs to be thrown to get the Stack Trace to analyze. This might be definitely problematic inside the tight loop, but there are ways to deal with this. First, you can shortcut the log message origin inspection (for production environment, for example) or use the excessive object allocation (and subsequent garbage collection calls) to your advantage to spot these tight loops with unintended log calls in them (you most likely don't want to have logs in the tight loops anyway). Another alternative is to resort to the original API: it is still there for you to use and there is nothing wrong with it if you know what is the purpose of explicitly provide the log context information. It just feels stupid to me to do so every single time just because the poor designed API asks you to do so.

If you liked the idea of the simplified logging on Android, there is easy way for you to hop the train. Just go to the following address:

https://github.com/actiwerks/logdroid

and either grab the copy of the entire project, or just download the jar file (located at: https://github.com/actiwerks/logdroid/blob/master/library/bin/logdroidlibrary.jar) and include it in your Android project. All you have to do to make the log system to work is to work is to import the correct package:

import objectforms.utils.prn;

Please note that while logdroid is available as the separate open source package in GITHub, it has been originally developed as part of the ObjectForms framework and it still keeps the original package name. Another aspect of this heritage is that prn.log(); call is platform independent and should work anywhere ObjectForms get ported to in the future. In order to fully integrate it with the native Android logging (including correctly filling the TAG argument), you need to connect the two systems at a start of your Android application or any similar appropriate moment. This can be done by calling the following method of the prn class :

public static void setPrinter(LogPrinter myPrinter);

There is implementation of the LogPrinter ready for you, in form of class:

actiwerks.logdroid.LogPlug;

All you need to do in your application is inserting this line of code :

prn.setPrinter(new actiwerks.logdroid.LogPlug());

and you are done. If you fail to provide this connection, the logging still works but it would resort to the platform neutral bottom line, System.out.println(); which in turn would omit the TAG information.

Hope you find the simplification to the default Android logging system useful and become a happy user of logdroid library. It only saves four key strokes at a time, but in the long run we hope it would be well worth the investment.