`PluginBuilder` reads builder fields that `GraalVmProcessor` does not register, so `LevelMatchFilter`, `SystemPropertyArbiter` and others fail in GraalVM native images
Los mantenedores suelen responder en 1 día
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- java
- Área
- observability
Línea de trabajo
The runtime side is PluginBuilder.injectFields() and validateFields(), which currently walk every declared field via TypeUtil.getAllDeclaredFields. The metadata side is GraalVmProcessor and its Annotations helper, which need to handle @PluginAttribute. Start by reproducing the native-image failure with the issue's log4j2.xml and demo classes, then check that GraalVmProcessorTest gets a fixture with a @PluginAttribute builder field. Done means the native output matches the JVM output and the new PluginBuilderTest passes.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Description
I first reported this to Spring Boot (spring-projects/spring-boot#52046) because their SpringProfileArbiter broke in our native image. Andy pointed out that the metadata comes from GraalVmProcessor, so the fix belongs here. After digging in, it isn't Spring specific. On current GraalVM CE a plain Log4j 2.26.1 app hits it with Log4j's own filters and arbiters.
There are two gaps between what PluginBuilder does at runtime and what GraalVmProcessor registers.
-
PluginBuilder.injectFields()andPluginBuilder.validateFields()take every declared field in the builder hierarchy (TypeUtil.getAllDeclaredFields) and callsetAccessibleon all of them.validateFields()then callsField.get()on each one, including fields with no plugin annotation.GraalVmProcessoronly registers the annotated fields. On GraalVM CE 25.0.2 this works by accident, becausegetDeclaredFields()hides fields that aren't registered. On GraalVM CE 25.4.4.1.1 (JDK 25.0.4)getDeclaredFields()returns all of them, soField.get()on astatic finalconstant or a static logger throwsMissingReflectionRegistrationErrorand the plugin isn't created. I get the same failure on 25.0.2 as soon as anything registers the builder type in the newerreachability-metadata.jsonformat, even when it lists only the annotated fields. -
GraalVmProcessordoesn't handle@PluginAttribute.PluginBuilderaccepts it on builder fields (the visitor lookup is generic) andRoutes.BuilderandKafkaAppender.Builderuse it, but those fields get no metadata. In a native image the attribute is rejected as invalid and the builder keeps its defaults. This one also fails on 25.0.2.
These builders in log4j-core 2.26.1 have fields that the shipped metadata doesn't cover. I found them by comparing declared fields against the reflect-config.json files in the jar, and I ran LevelMatchFilter and SystemPropertyArbiter natively.
- Every builder that extends
AbstractFilter.AbstractFilterBuilder(staticATTR_ON_MATCH/ATTR_ON_MISMATCH), soLevelMatchFilter,BurstFilter,StringMatchFilter,MutableThreadContextMapFilter SystemPropertyArbiter,EnvironmentArbiter,ClassArbiter(staticATTR_*constants) andScriptArbiter(staticLOGGER)PatternMatch.Builder(serialVersionUID)PosixViewAttributeAction.Builder(subst,filePermissions) andJmsAppender.Builder(jmsManager), plain fields with no annotationRoutes.Builder(pattern) andKafkaAppender.Builder(all attributes), which use@PluginAttributeon fields, so<Routes pattern="...">in aRoutingAppenderloses its pattern
Outside Log4j, Spring Boot's SpringProfileArbiter.Builder (static statusLogger) and SpringBootTriggeringPolicyBuilder (@PluginAttribute fields) have the same problems.
It fails quietly. The status logger prints errors and the configuration carries on without the plugin, so a filter disappears and lets through events it should deny, or a <Select> gets dropped and the appender loses its layout.
Configuration
Version: 2.26.1 (same code on 2.x at d1e96de)
Operating system: Linux (Docker, toolchain from ghcr.io/graalvm/native-image-community:25)
JDK: GraalVM CE 25.4.4.1.1 (JDK 25.0.4.1.1), default native-image options. GraalVM CE 25.0.2 only shows the @PluginAttribute problem. We first saw this in a Spring Boot app with GraalVM CE and Liberica NIK on JDK 25.0.4.
Logs
Native run on GraalVM CE 25.4.4.1.1 with the reproducer below (trimmed):
main ERROR Could not create plugin of type class org.apache.logging.log4j.core.config.arbiters.SystemPropertyArbiter for element SystemPropertyArbiter: org.graalvm.nativeimage.MissingReflectionRegistrationError: Cannot reflectively read or write field 'public static final java.lang.String org.apache.logging.log4j.core.config.arbiters.SystemPropertyArbiter$Builder.ATTR_PROPERTY_NAME'. [...]
at [email protected]/java.lang.reflect.Field.get(Field.java:440)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.validateFields(PluginBuilder.java:220)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.injectFields(PluginBuilder.java:203)
at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:123)
[...]
main ERROR Unable to invoke factory method in class org.apache.logging.log4j.core.config.arbiters.SystemPropertyArbiter for element SystemPropertyArbiter: java.lang.IllegalStateException: No factory method found for class org.apache.logging.log4j.core.config.arbiters.SystemPropertyArbiter
main ERROR Error capturing node data for node Console
main ERROR AttributeArbiter contains an invalid element or attribute "active"
main ERROR appender Console has no parameter that matches element Select
main ERROR Could not create plugin of type class org.apache.logging.log4j.core.filter.LevelMatchFilter for element LevelMatchFilter: org.graalvm.nativeimage.MissingReflectionRegistrationError: Cannot reflectively read or write field 'public static final java.lang.String org.apache.logging.log4j.core.filter.AbstractFilter$AbstractFilterBuilder.ATTR_ON_MISMATCH'. [...]
main ERROR Unable to invoke factory method in class org.apache.logging.log4j.core.filter.LevelMatchFilter for element LevelMatchFilter: java.lang.IllegalStateException: No factory method found for class org.apache.logging.log4j.core.filter.LevelMatchFilter
The No factory method found errors are just PluginBuilder falling back to a factory method after the builder fails. It's not #3871 again; the type-name fix from 2.25.3 is in place here.
Output on the JVM:
ARBITER INFO info message
CUSTOM INFO info message
ARBITER WARN warn message
FILTER WARN warn message
CUSTOM WARN warn message
Output in the native image (layout lost, filter gone, wrong <Select> branch):
info message
FILTER INFO info message
WRONG INFO info message
warn message
FILTER WARN warn message
WRONG WARN warn message
Reproduction
log4j2.xml:
<Configuration status="WARN">
<Appenders>
<Console name="Arbiter">
<Select>
<SystemPropertyArbiter propertyName="java.vm.name" propertyValue="does-not-match">
<PatternLayout pattern="WRONG %-5p %m%n"/>
</SystemPropertyArbiter>
<DefaultArbiter>
<PatternLayout pattern="ARBITER %-5p %m%n"/>
</DefaultArbiter>
</Select>
</Console>
<Console name="Filter">
<PatternLayout pattern="FILTER %-5p %m%n"/>
<LevelMatchFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
</Console>
<Console name="Custom">
<Select>
<AttributeArbiter active="true">
<PatternLayout pattern="CUSTOM %-5p %m%n"/>
</AttributeArbiter>
<DefaultArbiter>
<PatternLayout pattern="WRONG %-5p %m%n"/>
</DefaultArbiter>
</Select>
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Arbiter"/>
<AppenderRef ref="Filter"/>
<AppenderRef ref="Custom"/>
</Root>
</Loggers>
</Configuration>
demo/Main.java:
package demo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Main {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(Main.class);
logger.info("info message");
logger.warn("warn message");
}
}
demo/AttributeArbiter.java, a third-party plugin that uses @PluginAttribute on a builder field the way KafkaAppender.Builder does:
package demo;
import org.apache.logging.log4j.core.config.Node;
import org.apache.logging.log4j.core.config.arbiters.Arbiter;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
@Plugin(name = "AttributeArbiter", category = Node.CATEGORY, elementType = Arbiter.ELEMENT_TYPE, deferChildren = true, printObject = true)
public final class AttributeArbiter implements Arbiter {
private final boolean active;
private AttributeArbiter(boolean active) {
this.active = active;
}
@Override
public boolean isCondition() {
return active;
}
@PluginBuilderFactory
public static Builder newBuilder() {
return new Builder();
}
public static final class Builder implements org.apache.logging.log4j.core.util.Builder<AttributeArbiter> {
@PluginAttribute("active")
private String active;
@Override
public AttributeArbiter build() {
return new AttributeArbiter(Boolean.parseBoolean(active));
}
}
}
Build and run:
CP=log4j-api-2.26.1.jar:log4j-core-2.26.1.jar
javac -proc:full -Alog4j.graalvm.groupId=demo -Alog4j.graalvm.artifactId=demo -cp $CP -d classes demo/*.java
cp log4j2.xml classes/
java -cp classes:$CP demo.Main
native-image --no-fallback -cp classes:$CP -o app demo.Main
./app
The generated metadata for the demo plugin has no entry for AttributeArbiter$Builder:
[{"name":"demo.AttributeArbiter","methods":[{"name":"newBuilder","parameterTypes":[]}],"fields":[]}]
Proposed fix
I have a patch ready and can open a PR against 2.x:
PluginBuilderonly uses fields that have an annotation meta-annotated with@PluginVisitorStrategyor@Constraint. Those are the only fields it injects or validates anyway, so the runtime matches what the processor registers and doesn't depend on how a GraalVM version treats unregistered fields.GraalVmProcessor(and itsAnnotationshelper) handle@PluginAttribute, so builder fields that use it get registered. Nothing changes for method parameters.
With the patch the reproducer prints the same output natively as on the JVM, on GraalVM CE 25.4.4.1.1. The PR adds a PluginBuilderTest for the field filter and a @PluginAttribute builder field to the GraalVmProcessorTest fixture.
The other way to fix the first part would be for GraalVmProcessor to register all declared fields of builder types. I went with the runtime change because it also covers base classes the processor never sees and keeps the metadata small, but I'm fine either way.
- Lenguaje dominante
- Java
- Estrellas
- 3.6k
- Forks
- 1.8k
- Merge medio
- 5 d 6 h
- PR fusionados (30 d)
- 24
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Sin guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de apache/logging-log4j2
-
additivity attributeAbiertowaiting-for-maintainer
Dificultad 2/5 1-3 horas Aptitud para principiantes 63/100
apache/logging-log4j2#4475 ·
Los mantenedores suelen responder en 1 día
-
Migrate `log4j-api-test` tests to JUnit 5Quizá libre de nuevo Un pull request para esta issue se cerró sin fusionarse. Abiertoapi priority: P3 tests waiting-for-maintainer
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
apache/logging-log4j2#4430 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
`Rfc5424Layout` does not escape the `newLineEscape` replacement in SD-PARAM-VALUEPosiblemente ocupada @lunarbae628 la tomó hace 5 días. Abiertobug layouts priority: P3
apache/logging-log4j2#4464 · 2 comentarios · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
configuration enhancement layouts
Dificultad 4/5 3-5 días Aptitud para principiantes 55/100
apache/logging-log4j2#4463 ·
Los mantenedores suelen responder en 1 día
-
`evaluateOnStartup="true"` saves logs under wrong file names after missing scheduled rollQuizá libre de nuevo Un pull request para esta issue se cerró sin fusionarse. Abiertoappenders:Rolling bug priority: P1 waiting-for-maintainer
Dificultad 3/5 1-2 días Aptitud para principiantes 30/100
apache/logging-log4j2#4449 ·
Los mantenedores suelen responder en 1 día
Todos los issues de apache/logging-log4j2
Issues similares
-
untriaged
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
opensearch-project/opensearch-prometheus-exporter#680 ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 66/100
Los mantenedores suelen responder en 2 días
-
bug
Dificultad 1/5 Menos de una hora Aptitud para principiantes 78/100
-
Good First Issue
Dificultad 1/5 1-3 horas Aptitud para principiantes 88/100
hiero-ledger/hiero-sdk-java#3059 ·
Los mantenedores suelen responder en 1 día
-
bug live-tv platform:desktop platform:mobile platform:tv
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
fk0u/cleanyourtv-tahoe#102 ·
Los mantenedores suelen responder en 1 día