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

Classpath resource not found when using Spring Boot and GraalVM #2945

Closed
brendenehlers opened this issue Sep 11, 2024 · 5 comments
Closed

Classpath resource not found when using Spring Boot and GraalVM #2945

brendenehlers opened this issue Sep 11, 2024 · 5 comments

Comments

@brendenehlers
Copy link

Description

When using Spring Boot, Log4j 2.24.0, and GraalVM, the application cannot start because it can't find classpath resource log4j2.xml.

Error message:
java.io.FileNotFoundException: class path resource [org/springframework/boot/logging/log4j2/log4j2.xml] cannot be resolved to URL because it does not exist

Configuration

Version: 2.24.0

Operating system: MacOS/GraalVM

JDK: GraalVM 22

Logs

Logging system failed to initialize using configuration from 'null'
java.io.FileNotFoundException: class path resource [org/springframework/boot/logging/log4j2/log4j2.xml] cannot be resolved to URL because it does not exist
        at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:230)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.getConfigurationSource(Log4J2LoggingSystem.java:289)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.load(Log4J2LoggingSystem.java:281)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.loadConfiguration(Log4J2LoggingSystem.java:266)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.load(Log4J2LoggingSystem.java:244)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.loadDefaults(Log4J2LoggingSystem.java:230)
        at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(AbstractLoggingSystem.java:84)
        at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:61)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.initialize(Log4J2LoggingSystem.java:223)
        at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:332)
        at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:298)
        at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:246)
        at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:223)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138)
        at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
        at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81)
        at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64)
        at java.base@22.0.2/java.lang.Iterable.forEach(Iterable.java:75)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
        at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63)
        at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:370)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:330)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
        at com.example.log4j2test.Log4j2TestApplication.main(Log4j2TestApplication.java:10)
        at java.base@22.0.2/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
Application run failed
java.lang.IllegalStateException: java.lang.IllegalStateException: Could not initialize Log4J2 logging from classpath:org/springframework/boot/logging/log4j2/log4j2.xml
        at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:347)
        at org.springframework.boot.context.logging.LoggingApplicationListener.initialize(LoggingApplicationListener.java:298)
        at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEnvironmentPreparedEvent(LoggingApplicationListener.java:246)
        at org.springframework.boot.context.logging.LoggingApplicationListener.onApplicationEvent(LoggingApplicationListener.java:223)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138)
        at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
        at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81)
        at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64)
        at java.base@22.0.2/java.lang.Iterable.forEach(Iterable.java:75)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
        at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
        at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63)
        at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:370)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:330)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
        at com.example.log4j2test.Log4j2TestApplication.main(Log4j2TestApplication.java:10)
        at java.base@22.0.2/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
Caused by: java.lang.IllegalStateException: Could not initialize Log4J2 logging from classpath:org/springframework/boot/logging/log4j2/log4j2.xml
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.loadConfiguration(Log4J2LoggingSystem.java:275)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.load(Log4J2LoggingSystem.java:244)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.loadDefaults(Log4J2LoggingSystem.java:230)
        at org.springframework.boot.logging.AbstractLoggingSystem.initializeWithConventions(AbstractLoggingSystem.java:84)
        at org.springframework.boot.logging.AbstractLoggingSystem.initialize(AbstractLoggingSystem.java:61)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.initialize(Log4J2LoggingSystem.java:223)
        at org.springframework.boot.context.logging.LoggingApplicationListener.initializeSystem(LoggingApplicationListener.java:332)
        ... 20 more
Caused by: java.io.FileNotFoundException: class path resource [org/springframework/boot/logging/log4j2/log4j2.xml] cannot be resolved to URL because it does not exist
        at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:230)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.getConfigurationSource(Log4J2LoggingSystem.java:289)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.load(Log4J2LoggingSystem.java:281)
        at org.springframework.boot.logging.log4j2.Log4J2LoggingSystem.loadConfiguration(Log4J2LoggingSystem.java:266)
        ... 26 more

Reproduction

Here's a repo I created with a minimal example of the bug. Follow the steps in the README to reproduce the bug.

https://github.com/brendenehlers/log4j-graalvm-error

@ppkarwasz
Copy link
Contributor

@brendenehlers,

Thanks you for your report. As the name org/springframework/boot/logging/log4j2/log4j2.xml is a Spring Boot resource and you should report this problem to the Spring Boot project, so that they can add the appropriate Resource Metadata to their JARs or to the oracle/graalvm-reachability-metadata project.

Note that GraalVM requires a lot of metadata to decide which classes and resources to include. This metadata can be:

  • distributed with the libraries themselves: this is extremely rare. I don't an example of library with GraalVM metadata embedded.
  • distributed through oracle/graalvm-reachability-metadata: this is the most popular way. The Spring Boot project itself contributed a lot of metadata to that repository (e.g. for Logback, but not Log4j Core).
  • in your own project. See our GraalVM sample for an example of how to use the GraalVM tracing agent to generate metadata.

Remark: While the Log4j API does not requires any GraalVM metadata since the release of version 2.24.0, Log4j Core (the Reference Implementation of Log4j API) needs a lot of it. We will contribute that metadata to graalvm-reachability-metadata in the future, but for now you need to generate it yourself.

@brendenehlers
Copy link
Author

@ppkarwasz Thank you for the response, I'll bring this up to the Spring Boot team.

Appreciate the help!

@vy
Copy link
Member

vy commented Sep 12, 2024

@brendenehlers, I have the impression that there is a bit of a confusion here. Allow me to clarify certain concepts.

Log4j API and Log4j Core (the reference implementation of the Log4j API) are two different things. You can contrast them to SLF4J and Logback. Your application or its transitive dependencies might be using Log4j API as their choice of logging API. Though the backend, aka., the logging implementation, might be Log4j Core or Logback, or something else. The 2.24.0 release of the Log4j project published a Log4j API (i.e., the log4j-api artifact) that supports GraalVM out-of-the-box without necessitating any extra metadata configuration. That said, Log4j Core still requires manual configuration to get it working with GraalVM – this will be addressed by #2831 soon.

@brendenehlers
Copy link
Author

@vy Thank you for the clarification. It makes it much clearer as to what each package does.

I'll keep an eye on #2831 since that'll be an exciting development!

@ppkarwasz
Copy link
Contributor

I am closing this, since it can not be fixed by Log4j.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants