Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to configure java.util.logging on Android?

People also ask

What is Java Util logging?

java. util. logging. LogManager is the class that reads the logging configuration, create and maintains the logger instances. We can use this class to set our own application specific configuration.

What is the use of logger in Android?

A Logger object is used to log messages for a specific system or application component. Loggers are normally named, using a hierarchical dot-separated namespace. Logger names can be arbitrary strings, but they should normally be based on the package name or class name of the logged component, such as java.net or javax.

What is util package in Android?

util. Provides common utility methods such as date/time manipulation, base64 encoders and decoders, string and number conversion methods, and XML utilities.


This is now an FAQ for one of my projects, hopefully more people will find this here: java.util.logging works fine on Android. Please don't use anything else in your code, logging frameworks are like a pest in the Java world.

What is broken is the default logging handler shipped with Android, it ignores any log messages with level finer than INFO. You don't see DEBUG etc. messages.

The reason is the call to Log.isLoggable() in AndroidHandler.java:

https://github.com/android/platform_frameworks_base/blob/master/core/java/com/android/internal/logging/AndroidHandler.java

Here is how you fix it:

import android.util.Log;
import java.util.logging.*;

/**
 * Make JUL work on Android.
 */
public class AndroidLoggingHandler extends Handler {

    public static void reset(Handler rootHandler) {
        Logger rootLogger = LogManager.getLogManager().getLogger("");
        Handler[] handlers = rootLogger.getHandlers();
        for (Handler handler : handlers) {
            rootLogger.removeHandler(handler);
        }
        rootLogger.addHandler(rootHandler);
    }

    @Override
    public void close() {
    }

    @Override
    public void flush() {
    }

    @Override
    public void publish(LogRecord record) {
        if (!super.isLoggable(record))
            return;

        String name = record.getLoggerName();
        int maxLength = 30;
        String tag = name.length() > maxLength ? name.substring(name.length() - maxLength) : name;

        try {
            int level = getAndroidLevel(record.getLevel());
            Log.println(level, tag, record.getMessage());
            if (record.getThrown() != null) {
                Log.println(level, tag, Log.getStackTraceString(record.getThrown()));
            }
        } catch (RuntimeException e) {
            Log.e("AndroidLoggingHandler", "Error logging message.", e);
        }
    }

    static int getAndroidLevel(Level level) {
        int value = level.intValue();

        if (value >= Level.SEVERE.intValue()) {
            return Log.ERROR;
        } else if (value >= Level.WARNING.intValue()) {
            return Log.WARN;
        } else if (value >= Level.INFO.intValue()) {
            return Log.INFO;
        } else {
            return Log.DEBUG;
        }
    }
}

In the main activity/initialization code of your application:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    AndroidLoggingHandler.reset(new AndroidLoggingHandler());
    java.util.logging.Logger.getLogger("my.category").setLevel(Level.FINEST);
...

TL;DR: Yes, you could use some magic properties, or adb shell command, or even learn how the stupid built-in logging handler's DalvikLogging.loggerNameToTag converts category names to tags (which you would have to do for those magic properties and shell commands), but why bother? Isn't logging painful enough?


Generally one uses android.util.Log for logging on Android. There are some key advantages to using that logger, such as being able to use adb logcat to view logging output sent to those logs.

You can try put logging.properties in assets/ or res/raw/. If Android doesn't pick those up there, then one can use java.util.logging.LogManager.readConfiguration(java.io.InputStream) to force load it. (You can use the Resources and AssetManager classes to get the file as an InputStream).


At least on Android 4.3, with unchanged Handler, if you use

adb shell setprop log.tag.YOURTAG DEBUG

You can see messages logged with up to Level.FINE in logcat. I haven't figured out a way to log higher levels, but that's sufficient for me.


In case one of you only wants to route java.util.logging output from third party libraries, this can achieved pretty easily with SLF4J and its jul-to-slf4j bridge. This works for FINE and FINEST log statements, too, BTW.

Here's the maven dependency

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>${slf4j.version}</version>
</dependency>

To bootstrap it, put the following in your Application class, Roboguice Module or somewhere else where it gets executed before your first log statement. (Configuring this in assets/logging.propertiesseems not to work, unfortunately).

/*
 * add SLF4JBridgeHandler to j.u.l's root logger, should be done once
 * during the initialization phase of your application
 */
SLF4JBridgeHandler.install();

You can then either

  • configure all your log statements from assets/logback.xml (using logback-android). See here for a mapping of log levels.

  • or just use SLF4J-android to forward the log statements to logcat. To do so, just put the following dependency to your classpath, no further config required:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-android</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    

I implemented this successfully using

<properties>
    <slf4j.version>1.7.6</slf4j.version>
</properties>

Note:

  • Please read the part of the jul-to-slf4j doc that relates to performance carefully!
  • If you use the LogcatAppender make sure to keep in mind that the JUL log messages (except the ones with level finer than INFO) are routed to logcat by android. So make sure to apply appropriate filters that avoid duplicates.