Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject/Access Spring Bean into Log4j2 Plugin

I have a configuration properties class that I want to inject into a custom log4j2 RewritePolicy. e.g.

@Plugin(name = "MyPolicy", category = "Core", elementType = "rewritePolicy", printObject = true)
public class MyPolicy implements RewritePolicy {

    private MyPolicyProperties myPolicyProperties; // <-- want to inject/autowire this 

    public MyPolicy() {}

    @PluginFactory
    public static MyPolicy createPolicy() {
        return new MyPolicy();
    }

    @Override
    public LogEvent rewrite(LogEvent logEvent) {

        // do something with myPolicyProperties here

        return Log4jLogEvent.newBuilder()
            .setLoggerName(logEvent.getLoggerName())
            .setMarker(logEvent.getMarker())
            .setLoggerFqcn(logEvent.getLoggerFqcn())
            // ... etc
            .build();
    }
}
@ConfigurationProperties("app.mypolicy")
@Getter
@Setter
public class MyPolicyProperties {

    private String property1;
    private int property2;
    // ... etc
}

I've tried implementing an ApplicationListener to reconfigure log4j as described here but was can't seem to get the appender and/or rewritepolicy to configure. Also tried implementing ApplicationContextAware described here but also didn't work.

Is there anyway to access the MyPolicyProperties in MyPolicy?

like image 402
mpw2 Avatar asked Mar 26 '26 09:03

mpw2


1 Answers

It can be done but it is almost never pretty. This is because Log4j Plugins are loaded by Log4j's plugin system while Spring Beans are loaded by Spring. Furthermore, they are not instantiated at the same time.

If you are using Spring Boot the very first thing that will happen is for Log4j2 to initialize because SpringApplication requests a Logger. So there would be no way to resolve the Spring Bean at that point as it doesn't exist. Later, Spring's bootstrap process will initialize Log4j again and then during application setup it will initialize once or twice more. During these subsequent initializations the bean may be available.

Depending on the type of application you are using you may be able to locate Spring's ApplicationContext so that you can call getBean() and inject it.

There is no automatic way to do this via an annotation or something similar.

The simplest way to do it is to either add a static method in the target class that gets initialized to reference itself when Spring is initialized or to create another class with a method that initializes a static method to reference the Spring created bean. So Spring will cause these static methods to reference the bean it creates. Then have your Log4j plugin call that static method to get the bean reference. Once it is non-null you can save it in the plugin and after that it should function as you want.

like image 153
rgoers Avatar answered Mar 29 '26 11:03

rgoers