Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error using log4j2 api/core libraries with Android #3056

Closed
nick-j-white49 opened this issue Oct 4, 2024 · 4 comments · Fixed by #3071
Closed

Error using log4j2 api/core libraries with Android #3056

nick-j-white49 opened this issue Oct 4, 2024 · 4 comments · Fixed by #3071
Assignees
Labels
android bug Incorrect, unexpected, or unintended behavior of existing code

Comments

@nick-j-white49
Copy link

Description

Using log4j2 v2.24.0 (api and core) with Android throws error:

I/com.example: Caused by: java.lang.ClassNotFoundException: Didn't find class "java.lang.management.ManagementFactory" on path: DexPathList[[zip file "/data/app/~~MLF2ZshZzBIhJrgJjHw41g==/com.example-3Fbkjvp4obnGh8xK-dY_6A==/base.apk"],nativeLibraryDirectories=[/data/app/~~MLF2ZshZzBIhJrgJjHw41g==/com.example-3Fbkjvp4obnGh8xK-dY_6A==/lib/x86, /data/app/~~MLF2ZshZzBIhJrgJjHw41g==/com.example-3Fbkjvp4obnGh8xK-dY_6A==/base.apk!/lib/x86, /system/lib, /system_ext/lib]

gradle settings:

implementation ('org.apache.logging.log4j:log4j-api:2.24.1'){
    exclude group: 'com.sun.jmx', module: 'jmx'
    exclude group: 'javax.management'
}
implementation 'org.apache.logging.log4j:log4j-core:2.24.1'

Configuration

Version: 2.24.0

Operating system: Android SDK34

JDK: 1.8

Logs

I/com.example: Caused by: java.lang.ClassNotFoundException: Didn't find class "java.lang.management.ManagementFactory" on path: DexPathList[[zip file "/data/app/~~MLF2ZshZzBIhJrgJjHw41g==/com.example-3Fbkjvp4obnGh8xK-dY_6A==/base.apk"],nativeLibraryDirectories=[/data/app/~~MLF2ZshZzBIhJrgJjHw41g==/com.example-3Fbkjvp4obnGh8xK-dY_6A==/lib/x86, /data/app/~~MLF2ZshZzBIhJrgJjHw41g==/com.example-3Fbkjvp4obnGh8xK-dY_6A==/base.apk!/lib/x86, /system/lib, /system_ext/lib]]
@ppkarwasz ppkarwasz added bug Incorrect, unexpected, or unintended behavior of existing code android labels Oct 4, 2024
@ppkarwasz
Copy link
Contributor

Hi @nick-j-white49,

Thanks for the report. Do you have a stack trace that shows where that error occurred?

As far as I know no one among the core Log4j developers is using Android. Could you help us out, by submitting a minimal log4j-samples-android project as a PR to our apache/logging-log4j-samples?

We could integrate such a project into our integration tests (which currently cover JPMS, GraalVM, OSGi, but no Android).

@ppkarwasz ppkarwasz added waiting-for-user More information is needed from the user and removed waiting-for-maintainer labels Oct 4, 2024
@nick-j-white49
Copy link
Author

nick-j-white49 commented Oct 7, 2024

Full stack trace as follows:

I/example.log4jap: Rejecting re-init on previously-failed class java.lang.Class<org.apache.logging.log4j.core.lookup.JmxRuntimeInputArgumentsLookup>: java.lang.NoClassDefFoundError: Failed resolution of: Ljava/lang/management/ManagementFactory;
         at void org.apache.logging.log4j.core.lookup.JmxRuntimeInputArgumentsLookup.<clinit>() (JmxRuntimeInputArgumentsLookup.java:35)
         at java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[]) (Constructor.java:-2)
         at java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[]) (Constructor.java:343)
         at java.lang.Object org.apache.logging.log4j.core.util.ReflectionUtil.instantiate(java.lang.Class) (ReflectionUtil.java:188)
         at void org.apache.logging.log4j.core.lookup.Interpolator.<init>(org.apache.logging.log4j.core.lookup.StrLookup, java.util.List) (Interpolator.java:90)
         at void org.apache.logging.log4j.core.lookup.Interpolator.<init>(java.util.Map) (Interpolator.java:109)
         at void org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(org.apache.logging.log4j.core.LoggerContext, org.apache.logging.log4j.core.config.ConfigurationSource) (AbstractConfiguration.java:137)
         at void org.apache.logging.log4j.core.config.NullConfiguration.<init>() (NullConfiguration.java:32)
         at void org.apache.logging.log4j.core.LoggerContext.<clinit>() (LoggerContext.java:76)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.createContext(java.lang.String, java.net.URI) (ClassLoaderContextSelector.java:265)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.lambda$new$0$org-apache-logging-log4j-core-selector-ClassLoaderContextSelector() (ClassLoaderContextSelector.java:57)
         at java.lang.Object org.apache.logging.log4j.core.selector.ClassLoaderContextSelector$$ExternalSyntheticLambda1.get() (D8$$SyntheticClass:-1)
         at java.lang.Object org.apache.logging.log4j.util.LazyUtil$SafeLazy.value() (LazyUtil.java:113)
         at java.lang.Object org.apache.logging.log4j.util.Lazy.get() (Lazy.java:39)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getDefault() (ClassLoaderContextSelector.java:273)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(java.lang.String, java.lang.ClassLoader, java.util.Map$Entry, boolean, java.net.URI) (ClassLoaderContextSelector.java:152)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(java.lang.String, java.lang.ClassLoader, boolean, java.net.URI) (ClassLoaderContextSelector.java:125)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(java.lang.String, java.lang.ClassLoader, java.lang.Object, boolean, java.net.URI, java.lang.String) (Log4jContextFactory.java:241)
         at org.apache.logging.log4j.spi.LoggerContext org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(java.lang.String, java.lang.ClassLoader, java.lang.Object, boolean, java.net.URI, java.lang.String) (Log4jContextFactory.java:46)
         at org.apache.logging.log4j.spi.LoggerContext org.apache.logging.log4j.LogManager.getContext(boolean) (LogManager.java:118)
         at org.apache.logging.log4j.Logger org.apache.logging.log4j.LogManager.getLogger(java.lang.String) (LogManager.java:622)
         at org.apache.logging.log4j.Logger org.apache.logging.log4j.LogManager.getRootLogger() (LogManager.java:657)
         at void com.example.log4japi.MainActivity.<init>() (MainActivity.java:28)
         at java.lang.Object java.lang.Class.newInstance() (Class.java:-2)
         at android.app.Activity android.app.AppComponentFactory.instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) (AppComponentFactory.java:95)
 I/xample.log4jap:     at android.app.Activity androidx.core.app.CoreComponentFactory.instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) (CoreComponentFactory.java:45)
         at android.app.Activity android.app.Instrumentation.newActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) (Instrumentation.java:1253)
         at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:3353)
         at android.app.Activity android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.app.servertransaction.PendingTransactionActions, android.content.Intent) (ActivityThread.java:3601)
         at void android.app.servertransaction.LaunchActivityItem.execute(android.app.ClientTransactionHandler, android.os.IBinder, android.app.servertransaction.PendingTransactionActions) (LaunchActivityItem.java:85)
         at void android.app.servertransaction.TransactionExecutor.executeCallbacks(android.app.servertransaction.ClientTransaction) (TransactionExecutor.java:135)
         at void android.app.servertransaction.TransactionExecutor.execute(android.app.servertransaction.ClientTransaction) (TransactionExecutor.java:95)
         at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:2066)
         at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:106)
         at void android.os.Looper.loop() (Looper.java:223)
         at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:7656)
         at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2)
         at void com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run() (RuntimeInit.java:592)
         at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:947)
       Caused by: java.lang.ClassNotFoundException: Didn't find class "java.lang.management.ManagementFactory" on path: DexPathList[[dex file "/data/data/com.example.log4japi/code_cache/.overlay/base.apk/classes.dex", dex file "/data/data/com.example.log4japi/code_cache/.overlay/base.apk/classes3.dex", dex file "/data/data/com.example.log4japi/code_cache/.overlay/base.apk/classes4.dex", zip file "/data/app/~~IM0jLBxKndj1Iv1NsWAUrA==/com.example.log4japi-gluwbHKsoguOXmqwA790hA==/base.apk"],nativeLibraryDirectories=[/data/app/~~IM0jLBxKndj1Iv1NsWAUrA==/com.example.log4japi-gluwbHKsoguOXmqwA790hA==/lib/x86, /system/lib, /system_ext/lib]]
         at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:207)
         at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
         at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
         at void org.apache.logging.log4j.core.lookup.JmxRuntimeInputArgumentsLookup.<clinit>() (JmxRuntimeInputArgumentsLookup.java:35)
         at java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[]) (Constructor.java:-2)
         at java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[]) (Constructor.java:343)
         at java.lang.Object org.apache.logging.log4j.core.util.ReflectionUtil.instantiate(java.lang.Class) (ReflectionUtil.java:188)
         at void org.apache.logging.log4j.core.lookup.Interpolator.<init>(org.apache.logging.log4j.core.lookup.StrLookup, java.util.List) (Interpolator.java:90)
         at void org.apache.logging.log4j.core.lookup.Interpolator.<init>(java.util.Map) (Interpolator.java:109)
         at void org.apache.logging.log4j.core.config.AbstractConfiguration.<init>(org.apache.logging.log4j.core.LoggerContext, org.apache.logging.log4j.core.config.ConfigurationSource) (AbstractConfiguration.java:137)
         at void org.apache.logging.log4j.core.config.NullConfiguration.<init>() (NullConfiguration.java:32)
         at void org.apache.logging.log4j.core.LoggerContext.<clinit>() (LoggerContext.java:76)
 I/xample.log4jap:     at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.createContext(java.lang.String, java.net.URI) (ClassLoaderContextSelector.java:265)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.lambda$new$0$org-apache-logging-log4j-core-selector-ClassLoaderContextSelector() (ClassLoaderContextSelector.java:57)
         at java.lang.Object org.apache.logging.log4j.core.selector.ClassLoaderContextSelector$$ExternalSyntheticLambda1.get() (D8$$SyntheticClass:-1)
         at java.lang.Object org.apache.logging.log4j.util.LazyUtil$SafeLazy.value() (LazyUtil.java:113)
         at java.lang.Object org.apache.logging.log4j.util.Lazy.get() (Lazy.java:39)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getDefault() (ClassLoaderContextSelector.java:273)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(java.lang.String, java.lang.ClassLoader, java.util.Map$Entry, boolean, java.net.URI) (ClassLoaderContextSelector.java:152)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.selector.ClassLoaderContextSelector.getContext(java.lang.String, java.lang.ClassLoader, boolean, java.net.URI) (ClassLoaderContextSelector.java:125)
         at org.apache.logging.log4j.core.LoggerContext org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(java.lang.String, java.lang.ClassLoader, java.lang.Object, boolean, java.net.URI, java.lang.String) (Log4jContextFactory.java:241)
         at org.apache.logging.log4j.spi.LoggerContext org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(java.lang.String, java.lang.ClassLoader, java.lang.Object, boolean, java.net.URI, java.lang.String) (Log4jContextFactory.java:46)
         at org.apache.logging.log4j.spi.LoggerContext org.apache.logging.log4j.LogManager.getContext(boolean) (LogManager.java:118)
         at org.apache.logging.log4j.Logger org.apache.logging.log4j.LogManager.getLogger(java.lang.String) (LogManager.java:622)
         at org.apache.logging.log4j.Logger org.apache.logging.log4j.LogManager.getRootLogger() (LogManager.java:657)
         at void com.example.log4japi.MainActivity.<init>() (MainActivity.java:28)
         at java.lang.Object java.lang.Class.newInstance() (Class.java:-2)
         at android.app.Activity android.app.AppComponentFactory.instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) (AppComponentFactory.java:95)
         at android.app.Activity androidx.core.app.CoreComponentFactory.instantiateActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) (CoreComponentFactory.java:45)
         at android.app.Activity android.app.Instrumentation.newActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) (Instrumentation.java:1253)
         at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:3353)
         at android.app.Activity android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.app.servertransaction.PendingTransactionActions, android.content.Intent) (ActivityThread.java:3601)
         at void android.app.servertransaction.LaunchActivityItem.execute(android.app.ClientTransactionHandler, android.os.IBinder, android.app.servertransaction.PendingTransactionActions) (LaunchActivityItem.java:85)
         at void android.app.servertransaction.TransactionExecutor.executeCallbacks(android.app.servertransaction.ClientTransaction) (TransactionExecutor.java:135)
         at void android.app.servertransaction.TransactionExecutor.execute(android.app.servertransaction.ClientTransaction) (TransactionExecutor.java:95)
         at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:2066)
         at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:106)
 I/xample.log4jap:     at void android.os.Looper.loop() (Looper.java:223)
         at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:7656)
         at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2)
         at void com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run() (RuntimeInit.java:592)
         at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:947)

This seems to occur whenever an instance of org.apache.logging.log4j.Logger is returned (in the sample I will upload shortly, defined in the Activity scope). This does not cause any application crash however, and on further inspection in v2.24.1 I can see that once the logging configuration is set appropriately for the logger in use, logging commands are working as expected (pre-2.24 this was not the case!)

The issues I'm currently facing seem related to log4j2 config initialisation at this point. I only seem to be able to use the root logger: Logger log = LogManager.getRootLogger();

which by default has LogLevel.ERROR set. This can be overridden using e.g. Configurator.setLevel(log, Level.INFO);

If I try to use any other logger: Logger log = LogManager.getLogger(MainActivity.class);

again, Level.ERROR is the default, but I am then unable to change the logging level. This is presumably because no configuration is available, so no other loggers are defined. It seems I can't get the application to read in a configuration from src/main/assets (which should be available on the log4j classpath).

log4j2.properties:

# Root logger configuration
status = error
name = PropertiesConfig

# Appenders
appender.console.type = Console
appender.console.name = Console
appender.console.target = SYSTEM_OUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = [%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p- %m%n

# Root logger level and appenders
rootLogger.level = INFO
rootLogger.appenderRefs = stdout
rootLogger.appenderRef.stdout.ref = Console

logger.com.example.log4japi.MainActivity.name = com.example.log4japi.MainActivity
logger.com.example.log4japi.MainActivity.level = DEBUG
logger.com.example.log4japi.MainActivity.additivity = false
logger.com.example.log4japi.MainActivity.appenderRefs = stdout
logger.com.example.log4japi.MainActivity.appenderRef.stdout.ref = Console

Attempts to manually load using:

InputStream inputStream = getAssets().open("log4j2.properties");
ConfigurationSource source = new ConfigurationSource(inputStream);
context.start(ConfigurationFactory.getInstance().getConfiguration(context, source));

result in error:

java.lang.UnsupportedOperationException: This parser does not support specification "Unknown" version "0.0"

@github-actions github-actions bot added waiting-for-maintainer and removed waiting-for-user More information is needed from the user labels Oct 7, 2024
@nick-j-white49
Copy link
Author

PR submitted: apache/logging-log4j-samples#196

@ppkarwasz
Copy link
Contributor

@nick-j-white49,

Thank you for the stacktrace and the example. Right now the only problem seems the JmxRuntimeInputArgumentsLookup class, which should not fail on Android (where there is no JMX), but I'll check if there aren't any other surprises.

ppkarwasz added a commit that referenced this issue Oct 9, 2024
This fixes three issues encountered in the [`log4j-samples-android`](https://github.com/apache/logging-log4j-samples/tree/main/log4j-samples-android) test project:

1. Disables the `jvmrunargs` lookup on Android and fixes it on the other platforms. Previously, the lookup always returned `null`.
2. Switches the default context selector to `BasicContextSelector` on Android. `StackLocator` is broken on Android: it cannot use our JDK 8 code (missing `sun.reflect` classes), but also it cannot use our JDK 11+ code (missing multi-release JAR support). This causes `ClassLoaderContextSelector` to use two different logger contexts for the same classloader.
3. Fixes a `ParserConfigurationException` caused by the lack of XInclude capabilities in Android's XML parser. The fix to [LOG4J2-3531](https://issues.apache.org/jira/browse/LOG4J2-3531) didn't cover all the cases.

Closes #3056.
Part of #2832.
ppkarwasz added a commit that referenced this issue Oct 10, 2024
This fixes three issues encountered in the [`log4j-samples-android`](https://github.com/apache/logging-log4j-samples/tree/main/log4j-samples-android) test project:

1. Disables the `jvmrunargs` lookup on Android and fixes it on the other platforms. Previously, the lookup always returned `null`.
2. Switches the default context selector to `BasicContextSelector` on Android. `StackLocator` is broken on Android: it cannot use our JDK 8 code (missing `sun.reflect` classes), but also it cannot use our JDK 11+ code (missing multi-release JAR support). This causes `ClassLoaderContextSelector` to use two different logger contexts for the same classloader.
3. Fixes a `ParserConfigurationException` caused by the lack of XInclude capabilities in Android's XML parser. The fix to [LOG4J2-3531](https://issues.apache.org/jira/browse/LOG4J2-3531) didn't cover all the cases.

Closes #3056.
Part of #2832.
ppkarwasz added a commit that referenced this issue Oct 16, 2024
This fixes three issues encountered in the [`log4j-samples-android`](https://github.com/apache/logging-log4j-samples/tree/main/log4j-samples-android) test project:

1. Disables the `jvmrunargs` lookup on Android and fixes it on the other platforms. Previously, the lookup always returned `null`.
2. Switches the default context selector to `BasicContextSelector` on Android. `StackLocator` is broken on Android: it cannot use our JDK 8 code (missing `sun.reflect` classes), but also it cannot use our JDK 11+ code (missing multi-release JAR support). This causes `ClassLoaderContextSelector` to use two different logger contexts for the same classloader.
3. Fixes a `ParserConfigurationException` caused by the lack of XInclude capabilities in Android's XML parser. The fix to [LOG4J2-3531](https://issues.apache.org/jira/browse/LOG4J2-3531) didn't cover all the cases.

Closes #3056.
Part of #2832.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
android bug Incorrect, unexpected, or unintended behavior of existing code
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants