J2ME Polish
J2ME Polish 2.4 Documentation
Enough Software

Debug/Logging

Sometimes logging feels good.
J2ME Polish provides a logging framework for debugging purposes. The goals for the framework are:

  • Enable and disable different logging levels for specific classes or packages
  • Leave no traces, when disabled
  • Extensible: define your own logging levels, add your own log handlers
  • Allow to process and view log messages on real devices
  • last but not least: simplicity!

Programming

To create a log entry in your, a simple System.out.println() is used combined with the #debug preprocessing directive:

try {
	doSomething();
	//#debug
	System.out.println("doSomething() succeeded");
} catch (Exception e) {
	//#debug error
	System.err.println("doSomething() failed" + e);
}

If the last logged parameter is an exception, the logging framework will automatically print its stacktrace:

//#debug error
System.err.println("doSomething() failed" + e);

You can also tag a debug message with a log level as shown above. There are 5 predefined log levels, but you can also create your own log levels:

  • debug < info < warn < error < fatal < [userdefined]

Using the Log Framework for Debugging

As you will see below you can activate specific log levels for a class or a package. You can also check for a specific log level in your code using the #if directive:

//#if polish.debug.info
   int startTime = System.currentTimeMillis();
//#endif

doComplexCall();

//#debug info
System.out.println("complex call took " 
	+ (System.currentTimeMillis() - startTime) 
	+ " ms." );

In the above example we check if the info logging level is activated for this class. If that's the case we measure and log the duration of the call. You can check for any log level by querying for the preprocessing symbol polish.debug.${level}, and yes this includes user specified ones:

  • polish.debug.debug
  • polish.debug.info
  • polish.debug.warn
  • polish.debug.error
  • polish.debug.fatal
  • polish.debug.${userdefined}

Configuration

To activate the logging for your application, edit the <debug> section in your build.xml.

Log Filters and Levels

<debug 
	verbose="false"
	level="error"
	if="test" >
	<filter package="com.company.mail" level="info" />
	<filter class="com.company.mail.IMapServer" level="debug" />
</debug>

The example above will show log messages with the level info or higher in all classes of the package com.company.mail and log messages with the level debug or higher of the class com.company.mail.IMapServer. You can use any number of <filter> elements to finetune your log levels.
For all other classes the error log level will be active, as this is specified in the level attribute (<debug level="error" ...).

In the above example the logging is only active when the Ant property test is set to true, since we are using the if attribute: <debug if="test" .... Alternatively you might also want to use the unless attribute.

Custom Log Levels

You can define and activate your own log levels using the levels attribute of the <debug> element:

<debug 
	verbose="false"
	level="error"
	levels="memory,performance"
	if="test" >
	<filter package="com.company.mail" level="info" />
	<filter class="com.company.mail.IMapServer" level="debug" />
</debug>

You can now use such log levels like the predefined ones in your application:

//#debug memory
System.out.println("Free memory: " + Runtime.getRuntime().freeMemory() );

//#if polish.debug.performance
	long startTime = System.currentTimeMilis();
//#endif
...

Log Handlers

By default log entries are logged to the standard output stream - this is useful in an emulator, but only in few other circumstances.
Use log handlers for sending logged entries to other places as well.

display Handler

The display log handler shows logged entries on top of the screen. This handler requires that you use the J2ME Polish user interface:
The display log handler in action.

After some time without new log entries, the log will be hidden. Even when the log is shown, you can work normally with the application. You can influence the appearance and behavior with some optional parameters:

<debug verbose="false" level="error" if="test or log" > 
  <handler name="display">
     <!-- hide entries after 10 seconds: -->
     <parameter name="timeout" value="10s" />
     <!-- show maximum 30 log entries: -->
     <parameter name="max-entries" value="30" />
     <!-- specify used colors: -->
     <parameter name="background-color" value="#a333" />
     <parameter name="font-color" value="yellow" />
     <parameter name="shadow-color" value="rgb(0,0,0)" />
  </handler>
</debug>

bluetooth Handler

Send log entries directly to your Bluetooth enabled Desktop PC with the bluetooth log handler. For receiving the log entries you can use ${polish.home}/bin/enough-j2mepolish-bluetoothlogger.jar (call it from the command line using java -jar enough-j2mepolish-bluetoothlogger.jar).
Note that you need to have support for L2CAP connectivity, which is not supported on Windows when using the Microsoft Bluetooth stack. If that's the case for please deactivate that stack and use Widcomm or similar instead. On Linux and Mac OS X L2CAP is always supported (when Bluetooth is active).

<debug verbose="false" level="error" if="test or log" > 
  <handler name="bluetooth" />
</debug>

http Handler

You can also send log entries to a remote server using HTTP GET requests thanks to Vera Wahler's contribution:

<debug verbose="false" level="error" if="test or log" > 
  <handler name="http">
       <-- optional parameters -->
       <parameter name="server" value="http://www.j2mepolish.org/loghandler" />
  </handler>
</debug>

This log handler will create a GET request for each log entry. The following example is a simple Ruby script that reads received log entries:

#!/usr/bin/ruby
require 'webrick'
include WEBrick

s = HTTPServer.new( :Port => 8100)

class LogServlet < HTTPServlet::AbstractServlet
  def do_GET(req, res)
    hash = req.query
    puts "Time: "+hash['time'].to_s
    puts "Message: "+hash['message'].to_s
    puts "Classname: "+hash['classname'].to_s
    puts "LineNumber: "+hash['lineNumber'].to_s
    puts "Exception: "+hash['Exception'].to_s
    puts "Level: "+hash['level'].to_s
  end  
end

s.mount("/loghandler", LogServlet)

trap("INT") { s.shutdown }

s.start

Stack Traces

Emulator stacktraces usually only give the bytecode offset of an exception:

at com.company.product.ClassName.method(+20);

J2ME Polish can resolve such offsets automatically:

at com.company.product.ClassName.java:200

For making this possible, please install the jad decompiler from http://www.kpdus.com/jad.html to ${polish.home}/bin.

Last but not least don't forget to add a caught exception as the last parameter to a log entry in this way:

} catch (Exception e) {
	//#debug error
	System.err.println("doSomething() failed" + e);
}
back to top