Log4j2 on Android

2019-02-14 13:46发布

问题:

I'm trying to use log4j2 on Android Project (I'm working on Android Studio).

In order to simplify this question, I will explaine what I've done in a simple dummy project (I got the same error in the real project than in this dummy project).

I create a simple dummy project with a main activity.

I add the log4j2 libs...

This is the gradle:

apply plugin: 'com.android.application'

android {
    packagingOptions {
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/NOTICE'
    }
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.example.test20150130"
        minSdkVersion 19
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.android.support:support-v4:21.0.3'
    compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.1'
    compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.1'
}

I've reduced the log4j2.xml to this:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug">
<Appenders>
    <Console name="Console" target="SYSTEM_OUT">
        <ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>
        <PatternLayout pattern="%m%n" />
    </Console>
</Appenders>

<Loggers>
    <root level="INFO">
        <AppenderRef ref="Console"/>
    </root>
    <logger name="Queries" level="ALL" additivity="false">
        <AppenderRef ref="Console"/>
    </logger>
</Loggers>

On the Activity, I import the libraries...

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

But when I try to use them...

Logger logger= LogManager.getLogger ("Queries");
logger.error ("It works...");

I've got an error on the 'Logger logger= LogManager.getLogger ("Queries");'

01-30 00:49:29.413    1685-1685/com.example.test20150130 E/AndroidRuntime? FATAL EXCEPTION: main
Process: com.example.test20150130, PID: 1685
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.test20150130/com.example.test20150130.MainScreenActivity}: java.lang.NullPointerException
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.NullPointerException
        at org.apache.logging.log4j.util.ReflectionUtil$PrivateSecurityManager.getCallerClass(ReflectionUtil.java:301)
        at org.apache.logging.log4j.util.ReflectionUtil.getCallerClass(ReflectionUtil.java:214)
        at org.apache.logging.log4j.util.ReflectionUtil.getCallerClass(ReflectionUtil.java:193)
        at org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(ClassLoaderContextSelector.java:72)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:195)
        at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:41)
        at org.apache.logging.log4j.LogManager.getContext(LogManager.java:160)
        at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:492)
        at com.example.test20150130.MainScreenActivity.delayedHide(MainScreenActivity.java:162)
        at com.example.test20150130.MainScreenActivity.onPostCreate(MainScreenActivity.java:129)
        at android.app.Instrumentation.callActivityOnPostCreate(Instrumentation.java:1150)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2178)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
        at android.app.ActivityThread.access$800(ActivityThread.java:135)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:136)
        at android.app.ActivityThread.main(ActivityThread.java:5017)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
        at dalvik.system.NativeStart.main(Native Method)

I'm not sure where the log4j2.xml file should be, so I trayed to put it on \src, on \src\main\java\com\example\test20150130 (same directory than the main activity), Test20150130\app\build\outputs\apk (same directory than the apk),...

Due to the error information, I tryed the getLogger everywhere: initially on the onCreate, then, I trayed it on an onClick event, but I got the same error.

(When I trayed to debug it, the sources I see are not aligned with the real execution...)

I had log4j already working on the Android project, but I've just migrated a Java EE project to log4j2 and I want to do the same on the Android project...

The log4j2 documentation has very few information about Android. It just says there are several modules not working on Android (JNDI, JMX,...), but nothing else... Maybe it requires internally those modules (JNDI?)...

Looking for information, I've founded this (https://issues.apache.org/jira/browse/LOG4J2-446?jql=project%20%3D%20LOG4J2%20AND%20text%20~%20android) but I did'n find a solution...

Is it possible to use log4j2 on Android?

Thank you very much in advance

回答1:

I've finally have what I was looking for...

I'm working with Android, and I was unable to recover loggers by name (LogManager.getLogger ("xxx") crashes the App in the worst way possible...)

I think the problem starts when it looks for the log4j2.xml. I put the file everywhere, but it doesn't work... ...so, I wanted to provide the log4j2.xml content into a String...

Here it is what I've done...

    String log4j2xmlFileContent=getLog4j2xmlContent();//Content of my log4j2.xml

    // convert String into InputStream
    InputStream is = new ByteArrayInputStream(log4j2xmlFileContent.getBytes());

    ConfigurationSource source=null;
    try{
        source = new ConfigurationSource(is);
    } catch (IOException ioe){
        ioe.printStackTrace();
    }

    Configuration config = org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory.getInstance().getConfiguration(source);
    loggerContext = (LoggerContext) LogManager.getContext();
    try {
        //loggerContext.stop();
        loggerContext.start(config);
    } catch (Exception e){
        e.printStackTrace();
    }
    return loggerContext;

and now, I can use that loggerContext to get my loggers...

    loggerHitosCarga = context.getLogger("HitosCarga");
    loggerPeticiones = context.getLogger("Peticiones");
    loggerQueries = context.getLogger("Queries");
    loggerDepuracionActual=context.getLogger("DepuracionActual");

    loggerDepuracionActual.warn("FUNCIONAAAAA!!!!..");        
    loggerHitosCarga.info("Loggers inicializados...");

Now I only have to review and improve it a little bit, but it works...



回答2:

Based on your own answer but with simplified code (using Configurator.initialize() instead of XmlConfigurationFactory etc.):

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;

// Content of log4j2.xml
String log4j2xmlFileContent = getLog4j2xmlContent(); 

// convert String into InputStream
InputStream is = new ByteArrayInputStream(log4j2xmlFileContent.getBytes());

try {
    ConfigurationSource source = new ConfigurationSource(is);
    return Configurator.initialize(null, source);
} catch (IOException e) {
    e.printStackTrace();
}
return null;

Note that:

  • this code must run before the first call of e.g. LogManager.getLogger()
  • the member function Configurator.initialize() is not part of the log4j2 public API (see here)

See also LOG4J2-952 and Log4jConfigure.java