Wednesday, November 23, 2011

Why logging with Log4j does not work in Android

If you put log4j.jar and a log4j.properties file in your Android's application classpath, you will investigate the following stack trace in LogCat.

11-23 09:44:56.947: D/dalvikvm(1585): GC_FOR_MALLOC freed 3278 objects / 311568 bytes in 31ms
rejecting opcode 0x21 at 0x000a
rejected Lorg/apache/log4j/config/PropertySetter;.getPropertyDescriptor
(Ljava/lang/String;)Ljava/beans/PropertyDescriptor;
Verifier rejected class Lorg/apache/log4j/config/PropertySetter;
Exception Ljava/lang/VerifyError; thrown during Lorg/apache/log4j/LogManager;.
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x400259f8)
FATAL EXCEPTION: main
java.lang.ExceptionInInitializerError
at org.slf4j.impl.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:64)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:253)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:265)
...
Caused by: java.lang.VerifyError: org.apache.log4j.config.PropertySetter
at org.apache.log4j.PropertyConfigurator.parseAppender(PropertyConfigurator.java:772)
at org.apache.log4j.PropertyConfigurator.parseCategory(PropertyConfigurator.java:735)
at org.apache.log4j.PropertyConfigurator.configureRootCategory(PropertyConfigurator.java:615)
at org.apache.log4j.PropertyConfigurator.doConfigure(PropertyConfigurator.java:502)
at org.apache.log4j.PropertyConfigurator.doConfigure(PropertyConfigurator.java:547)
at org.apache.log4j.helpers.OptionConverter.selectAndConfigure(OptionConverter.java:483)
at org.apache.log4j.LogManager.(LogManager.java:127)
... 20 more

The problem is, that log4j uses classes of java.beans package e.g. PropertyDescriptor. Not all classes of this package are supported in Android. See javadoc of Android's java.beans package.

There is a project called android-logging-log4j, which provides a convenient way to configure the log4j system properly. It also provides an appender for LogCat.

I filed a feature request to support more classes from java.beans package in the Android issue tracker.

5 comments:

turacma said...

Thanks for building this, but I'm having problems using it.

When I build my application it tells me that no appenders and no configuration has been applied to logger. I suspect this is because I'm incorrectly interpretting how to add the Configurator to the class path.

Can you please clarify how to do this?

Unknown said...

@turacma please try out the docu at android-logging-log4j

pewu said...

Dear Rolf,

Is it possible to create logfile as i.e. c:\myapp.log instead of Environment.getExternalStorageDirectory() + File.separator + "myapp.log" as described in the quickstart example?

What is your prefered way of viewing Android logs? Logcat? Other?

Best regards,
pewu

Anonymous said...

Hi Rolf,

I'm having problems getting this to work. I'm still getting the ExceptionInInitializerError, even though I'm using your LogConfigurator.

VFY: rejected Lorg/apache/log4j/config/PropertySetter;.getPropertyDescriptor (Ljava/lang/String;)Ljava/beans/PropertyDescriptor;
Verifier rejected class Lorg/apache/log4j/config/PropertySetter;
Exception Ljava/lang/VerifyError; thrown while initializing Lorg/apache/log4j/LogManager;

FATAL EXCEPTION: main
java.lang.ExceptionInInitializerError
at org.apache.log4j.Logger.getRootLogger(Logger.java:135)
at de.mindpipe.android.logging.log4j.LogConfigurator.configure(LogConfigurator.java:92)


It seems that LogConfigurator is using Logger, which is using PropertySetter.getPropertyDescriptor, which returns a java.beans.PropertyDescriptor, which is rejected by Android. If I understand your post correctly, this is not supposed to happen.

Can you tell me what's wrong here?


Thanks,
Tom

JD from Oaktown said...

This is very exciting. Can you please comment re: are asynch appenders avail with this? Will I be able to log asynchronously (similar to the original Log4j??)?

You should follow me
on twitter