Logback Groovy configuration and GraalVM

Viewed 1411

I'm attempting to use a groovy configuration file for logback used by my GraalVM compiled application.

When running it and compiling it normally everything is fine, but when I try to compile against Graal I'm facing some issues that I cannot understand how to resolve.

So, out of the without any particular configuration passed to Graal I get the following error during compilation:

Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of net.logstash.logback.encoder.LogstashEncoder are allowed in the image heap as this class should be initialized at image runtime. Object has been initialized by the io.micr
onaut.runtime.Micronaut class initializer with a trace: 
        at net.logstash.logback.encoder.LogstashEncoder.<init>(LogstashEncoder.java:27)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:80)
        at org.codehaus.groovy.reflection.CachedConstructor.doConstructorInvoke(CachedConstructor.java:74)
        at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1732)
        at groovy.lang.MetaClassImpl.invokeConstructor(MetaClassImpl.java:1556)

I tried the very lazy approach of allowing initialization of the class during build time by doing this:

--initialize-at-build-time=net.logstash.logback.encoder.LogstashEncoder

This only resulted in various other logstash related classes requiring this option, so I went ahead and added a rule for the whole package like so:

--initialize-at-build-time=net.logstash.logback

This did not resolve the problem but in turn resulted in the following error during compilation:

com.oracle.svm.core.util.UserError$UserException: Classes that should be initialized at run time got initialized during image building:
 ch.qos.logback.classic.gaffer.GafferConfigurator the class was requested to be initialized at build time (from the command line). ch.qos.logback.classic.gaffer.GafferConfigurator has been initialized without the native-image initialization instrumentation and the stack trace can't be tracked. Try avoiding to initialize the class that caused initialization of ch.qos.logback.classic.gaffer.GafferConfiguratorgroovy.lang.GroovySystem the class was requested to be initialized at build time (from the command line). io.micronaut.runtime.Micronaut caused initialization of this class with the following trace:
        at ch.qos.logback.classic.gaffer.GafferConfigurator.$getStaticMetaClass(GafferConfigurator.groovy)
        at ch.qos.logback.classic.gaffer.GafferConfigurator.<init>(GafferConfigurator.groovy)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at ch.qos.logback.classic.gaffer.GafferUtil.newGafferConfiguratorInstance(GafferUtil.java:52)
        at ch.qos.logback.classic.gaffer.GafferUtil.runGafferConfiguratorOn(GafferUtil.java:41)
        at ch.qos.logback.classic.util.ContextInitializer.configureByResource(ContextInitializer.java:67)
        at ch.qos.logback.classic.util.ContextInitializer.autoConfig(ContextInitializer.java:150)
        at org.slf4j.impl.StaticLoggerBinder.init(StaticLoggerBinder.java:84)
        at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:55)
        at org.slf4j.LoggerFactory.bind(LoggerFactory.java:150)
        at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:124)
        at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:412)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:357)
        at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:383)
        at io.micronaut.runtime.Micronaut.<clinit>(Micronaut.java:46)

I tried various permutations of rules regarding allowing and disallowing initialization on build or runtime but none of them worked.

So my question is, how am I supposed to overcome this? I'm trying to figure out the class that causes the initialization but I'm unable to do so as of now.

Has anyone managed to get logback to work with a groovy configuration file and successfully compile into a GraalVM image?

1 Answers

Due to how dynamic Groovy is it is harder to get operational on GraalVM nativeimage (but not impossible). I recommend you run the application through the tracing agent and to see what reflection configuration is required to get your logback.groovy file operational.

Build the application into a JAR and run the application with:

java -agentlib:native-image-agent=config-output-dir=META-INF/native-image -jar build/myjar-all.jar

Then look at the generated reflect-config.json file for entries relating to logback and include those in your configuration.

Alternatively you can avoid the hassle by using logback.xml

Related