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.
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.
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.properties
seems 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:
INFO
) are routed to logcat by android. So make sure to apply appropriate filters that avoid duplicates.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With