Powerful Logging in Java ME

By Johan Karlsson, originally published November 2009, updated February 2010  

This technical article explains how to add logging to your MIDlets using the Microlog open-source logging library.

Getting Started with Microlog
Using the Bluetooth Server
Logging Destinations
Log Levels and Filtering


You have just developed your new cool MIDlet, the one that is going to rule the world. It runs like a well oiled machine on the emulator. But when you download and install it on your target device, the MIDlet seems to take ages to start up. Finally, you see the splash screen. Oh no! The MIDlet crashes and you get an error pop-up saying "Application Error," and the MIDlet shuts down. What happened? This is not the way you pictured it. Is there something that shows what really happened behind the scenes?

Have you been in a situation like this? Have you ever wanted to log from your MIDlet? Read on, and I will teach how to add powerful logging to your MIDlets.

Getting Started with Microlog

You may have considered doing your own logging facility. But why not use an existing solution? An easy-to-use solution exists: The Microlog open-source logging library. It is based on the well known Log4j API or logging library, but has been created from the ground up with Java ME limitations in mind.

The library is released with Apache Software License V2. Thus you can use it in your own open-source projects, as well as in commercial applications. But let's get down to business and do some programming.

To add logging to your MIDlet, follow these steps:

  1. Download Microlog.
  2. Add the Microlog jar to your project.
  3. Create your MIDlet with logging statements.
  4. Configure Microlog.
  5. Build and run your MIDlet.

I will not go into detail about the first two items. Please refer to the instructions for the specific IDE that you are using. Starting at step 3, the source code is as follows. (For your convenience, I have attached all example source code files and configuration files.)


package com.jayway.midlet.techtip;

import java.io.IOException;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.*;
import net.sf.microlog.core.Logger;
import net.sf.microlog.core.LoggerFactory;
import net.sf.microlog.core.PropertyConfigurator;

 * The SimpleLoggingMidlet shows how simple it is to add logging to a midlet.
 * It has a simple GUI that let you try out logging.
 * N.B. there has to be some kind of GUI, otherwise it wont work in Suns WTK.
 * @author Johan Karlsson
public class SimpleLoggingMidlet extends MIDlet implements CommandListener {

    // A logger instance for this class
    private static final Logger log = LoggerFactory.getLogger(SimpleLoggingMidlet.class);
    private Display display;
    private Form form;
    private Command logCommand = new Command("Log", Command.OK, 1);
    private Command exitCommand = new Command("Exit", Command.EXIT, 1);

     * Constructor.
    public SimpleLoggingMidlet() {
        // Configure Microlog

     * @see javax.microedition.midlet.MIDlet#startApp()
    public void startApp() {
        log.info("Starting application");

        if (form == null) {
            log.debug("Creating a new Form");
            form = new Form("Simple Logging");
            display = Display.getDisplay(this);


     * @see javax.microedition.midlet.MIDlet#pauseApp() 
    public void pauseApp() {
        log.info("Pausing application");

     * @see javax.microedition.midlet.MIDlet#destroyApp(boolean)
    public void destroyApp(boolean unconditional) {
        log.info("Destroying application");

        // Shutdown Microlog gracefully

     * @see CommandListener#commandAction(javax.microedition.lcdui.Command, javax.microedition.lcdui.Displayable) 
    public void commandAction(Command command, Displayable displayable) {
        if (command == logCommand) {
            log.debug("User pressed the log button.");
        } else if (command == exitCommand) {
            log.debug("Exit button was pressed");


As you can see, the code is really simple. You create a Logger as a constant, that is, a static final class variable. For each class that you need to log, you add the same line of code except that you change the argument to match the class that you are using the logging in. The class name is then used as the name for the logger. This is handy within the log to distinguish between where the actual logging was performed. To do the actual logging, just add this simple line of code:


The debug() method is called when logging at debug level. There are other methods for different levels. How the level works is discussed later in the article. The set-up is equally simple, you add one line of code:


Notice that this should only be done once in an application, and this is why it is recommended to put it in the constructor of the main class. When developing a MIDlet, that is, it should always be in the constructor of the MIDlet. This ensures that it executes only once in the MIDlet's lifetime.

To ensure that Microlog shut down correctly, you should add a call to LoggerFactroy.shutdown() in the destroyApp() method. The PropertyConfigurator looks for a file called microlog.properties that is in the root of your jar. Put the properties file in your resource directory. This way the properties file is packaged in the JAR file when you build your project. Edit it to look like the example below.

# This is a simple Microlog configuration file

The PropertyConfigurator reads the property file that is packaged in the JAR file. By default it looks for the microlog.properties file, but it is possible to set your own file name. By using the PropertyConfigurator, you avoid putting predefined values in your code. This is good. On the other hand you must rebuild the JAR file each time you change the properties file.

Another solution is to use the MidletPropertyConfigurator. It first searches the JAD file and then checks the properties file for properties. Consequently, it is possible to change the Microlog configuration without rebuilding the JAR file. This is a very handy solution. If you forget to configure Microlog, it configures itself automatically. It is a simple configuration, using the ConsoleAppender with the SimpleFormatter -- the simplest possible logging that is available in Microlog, but it works on all devices.

Let me show how simple it is to change the logging. All you have to do is change the configuration file and rebuild the jar. The following example shows how to add logging to the record store and change the layout of the log output.

# Another simple Microlog configuration file. We now log to two different
# destinations; the console and the record store.
microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T

We have added the RecordStoreAppender to log to the record store. The formatter has changed from the SimpleFormatter to the PatternFormatter. The SimpleFormatter uses a predefined pattern for logging output. This is a good starting point, but in most cases you want to configure the logging output yourself.

The PatternFormatter lets you decide on how the logging pattern should look like. In this case we print the class name, the priority, the message and the Throwable object. If no Throwable is logged, this part is skipped.

Now compile and run the MIDlet once more, but with the new configuration file. The MIDlet logs to the record store while executing the MIDlet. Afterwards, when you have exited the MIDlet, you start the prepackaged record store log viewer. This is how it looks in action:


Using the Bluetooth Server

But that is not all! Many developers use Bluetooth to send their MIDlets to the target, to avoid the tedious need to connect and disconnect USB cables. If you are one of those developers, you might want to use the BluetoothSerialAppender. It sends the log directly to your computer from your target device. Looking at the log on your computer is much more convenient than viewing the log on a small mobile screen.

The following picture shows the Bluetooth server in action. Notice that it is possible to connect several clients at the time. I am using an older Sony Ericsson P910 device (in general, Microlog executes on older devices without problem).


Logging Destinations

But wait, there is even more. You have a myriad of logging destinations available in Microlog. Some of them are on-device, while others send the log to a remote device. In early stages of development, it is most convenient to use the on-device logging (or Bluetooth). Later in the development cycle, it is often more suitable to use remote device logging.

My favorite on-device logging destination is a file. On many devices, it is possible to read the log on the device. Most of the time I transfer the file to my computer and view it in my favorite editor. (If you are a dedicated Unix lover, use grep to find what you are looking for.)

When to use it
Use the emulator and log in the output window.
To view the log on the device.
To view the log on the device.
To view the log on the device.
To have a log to view on your computer.
To view the log on the device.
To log from the device to your computer and view the log in real time. A server with a simple GUI is provided with Microlog.
To log to a HTTP server. A sample HTTP server is provided with Microlog.
To send an SMS when something goes wrong.
To send an MMS or e-mail when something goes wrong.
To send to a socket server. A sample socket server is provided with Microlog.
To log to a syslog daemon on a remote server. A syslog daemon is a standard logging server that is available on the most common operating systems.
To log to a cloud, such as an Amazon S3 account. The file can be viewed by any S3 browser.

Log Levels and Filtering

One of the most important functions in a logging framework is the ability to filter your logging statements, just like Log4j. In Microlog, this is solved by assigning different levels to your logging statements.

It is important to use the right level when logging. Otherwise the logs will be flooded and performance will most likely be affected in a negative way.

When you set a level in Microlog, you logs everything at the specified level and above. For example, if you choose to log at level DEBUG, everything that is between level FATAL to level DEBUG will be put in the log. The following examples use one logging level for the entire application.

Since version 2.0 of Microlog, it has been possible to assign different levels to different classes. Let us assume that you have a MIDlet that is getting a big, that is, you have many classes. The logs get flooded by logging outputs, but you do not want to remove all important logging statements as most of them are there for a good reason. In such cases, it is possible to choose to only enable those classes that are relevant at the moment. For example, you are hunting down a bug and you know that is in a particular package. Look at this example:

microlog.rootLogger=ERROR, A1, A2


microlog.appender.A1.formatter.pattern=%c{1} [%P] %m %T


First, you set the root logger: You set the logging level and specify two appenders. We set the level to ERROR, which always is a good choice for the root logger. Whenever a logging is done at ERROR or FATAL, it gets logged.

You give the appenders symbolic names, in this case A1 & A2. The setup of the appenders and the formatter is the same, except that we insert the symbolic name. Notice that we we use the default settings for the RecordStoreAppender. At the end we override the ERROR level by setting the DEBUG level to all classes in the com.jayway.midlet.techtip package.

The property for setting the level is the string microlog.logger concatenated with the name of the package. It is possible add several packages and their special level. It is even possible to define the level for a set of packages. For example, you can set a special level for com.jayway and its inherent packages. All other packages will inherit the ERROR level from the root logger.

The following table shows the different logging levels available in Microlog. The first level, FATAL, always has the highest priority.

Log Level
When to Use
Severe error that causes the application to terminate prematurely.
An error that causes the application to malfunction, but it could continue.
Warns that something happens that might cause problems in the future.
Interesting information, like when the application starts, exits, etc. In a MIDlet it should be the first statements in the startApp(), pauseApp() and destroyApp()
Detailed information about the flow in the application.
Even more detailed information about the flows and variables.


This article shows how easy it is to add powerful logging to your MIDlet. It is done by simply adding the jar and a configuration file to your project. Once this is done, it is a matter of editing the configuration file to your liking.

Logging is an essential tool for embedded developers, and a nice companion to a debugger. It will help you in situations where using an emulator is not a viable solution. In Microlog, it is also possible to use in a headless environment, that is, an embedded device without a GUI.

For more tips and tricks, see the official Microlog blog. Happy logging!


Rate This Article
Terms of Use