views:

2939

answers:

7
+10  Q: 

Logging in J2ME

Hi,

What logging solutions exist for j2me?

I'm specifically interested in easily excluding logging for "release" version, to have a smaller package & memory footprint.

+1  A: 

I've used MIDPLogger to some acceptable level in a production application, although I have found it has more use after integrating into the application rather than as another Midlet in suite or so forth. I also found MicroLog but haven't used it to any great detail.

Scott Bennett-McLeish
+12  A: 

MicroLog is sure bet. It is a small logging library for Java ME (J2ME) like Log4j. It has support for logging to console, file, RecordStore, Canvas, Form, Bluetooth, a serial port (Bluetooth, IR, USB), Socket(incl SSL), UDP, Syslog, MMS, SMS, e-mail or to Amazon S3.

http://sourceforge.net/projects/microlog/

darius
MicroLog looks very nice, but it needs CLDC 1.1
Casebash
I found a library called [J4me](http://code.google.com/p/j4me/wiki/Logging) that will run on any device. Microlog looks better if you can manage it though
Casebash
Actually, J4me looks too simplistic for my needs (only really provides logging levels). I think I'll roll my own using Proguard
Casebash
+6  A: 

If you are using preprocessing and obfuscation with Proguard, then you can have a simple logging class.

public class Log {
  public static void debug(final String message) {
    //#if !release.build
    System.out.println(message);
    //#endif
  }
}

Or do logging where ever you need to. Now, if release.build property is set to true, this code will be commented out, that will result in an empty method. Proguard will remove all usages of empty method - In effect release build will have all debug messages removed.

Edit:

Thinking about it on library level (I'm working on mapping J2ME library) I have, probably, found a better solution.

public class Log {
  private static boolean showDebug;

  public static void debug(final String message) {
    if (showDebug) {
      System.out.println(message);
    }
  }

  public static void setShowDebug(final boolean show) {
    showDebug = show;
  }
}

This way end developer can enable log levels inside library that he/she is interested in. If nothing will be enabled, all logging code will be removed in end product obfuscation. Sweet :)

/JaanusSiim

JaanusSiim
How would the code be removed in the second version? You have removed the preprocessing commands
Casebash
Preprocessing part is in application code around 'Log.setShowDebug(true)'. This way 'showDebug' will always be false and ProGuard magic will happen. You may need to play with optimization passes number.
JaanusSiim
+3  A: 

The Series60 and UIQ phone that have a Sun virtual machine modified by Symbian itself have Standard Output redirection.

Not only can you capture System.out but Throwable.printStackTrace() also works.

On early handsets, You would need to write a C++ application that hooks into the standard library server process. Symbian produced the Redirector application that could capture the VM standard output to a console or a file.

On newer handsets, a "redirect://" GCF protocol was introduced that could read the VM standard output into a Java byte[] or String object (you would want to do that in a separate MIDlet) and the Redirector application was rewritten in Java.

On the newest J9 VM used in Series60 3rd Edition Feature Pack 2 handsets (and later), you may need to try "redirect://test" instead.

QuickRecipesOnSymbianOS
+5  A: 

You can use the -assumenosideaffects in proguard to completley remove your logging class:

-assumenosideeffects public class logger.Logger {*;}

Rather than having to preprocess.

edsumner
A: 

I wrote a bytecode optimizer, and because of the format of class files you can point to the UTF encoding of classname & function which allows you to output logs with MyClass.someFunc() (you can process the signature if you want to get the types) which allows you to do something like the C style debug using LINE & FILE macros.

A: 

Using conditional compilation of the logger class does not solve the problem of completely removing logging statements because you will quite often log more than a simple string. You will look up variable values and then assemble them into strings, e.g.: WhateverLog.log( "Loaded " + someclass.size() + " foos" ).

Now if you only leave out the body of WhateverLog.log (as shown in the accepted solution), you will still leave a lot of unnecessary code in, including String concatenation (and thus a StringBuffer creation). That's why you'd better use a byte code post processing tool like proguard (already mentioned). Proguard's -assumenosideeffects will allow its optimizer to remove not only the logging statements but also all code whose results would only be used by the logging call.

Otm Shank
I do have to disagree :P As it is mentioned - it only works if you use proguard. After commenting the content of debug() method out, you will have an empty method that will be removed by proguard. This will mean that all method calls will also be removed - You will not have any useless code ;)
JaanusSiim