What are the available options to retrieve Spring-managed beans in a Log4J Appender inside a Spring-managed web application?

StackOverflow https://stackoverflow.com/questions/1730634

Question

My current build lead has a great idea in theory - construct a custom Log4J appender that takes in Spring-managed beans and uses them to log errors to various other sources than just the standard log file. However, other than creating a singleton initialized at startup with the application context (code in just a moment), I can't seem to think of any other options of retrieving a Spring managed bean in a Log4J appender.

public class SpringSingleton implements ApplicationContextAware {
    private static ApplicationContext context;
    public SpringSingleton() {
        super();
    }
    public static ApplicationContext getContext() {
        return SpringSingleton.context;
    }
    public void setApplicationContext(ApplicationContext context) {
        if(SpringSingleton.context != null) {
            throw new IllegalStateException("Context is already set!");
        }
        SpringSingleton.context = context;
    }
}

Ideally, these properties could be set just like beans in Spring via dependency injection - the bean references will never change, no matter how many appenders are initialized. Any ideas?

Was it helpful?

Solution

You're going to have a boostrap problem since log4j has to be initialized before Spring. Whether you're using a custom configuration or Log4j's standard initializer, it has to be up before application context is.

Now, you could in theory make your custom appenders "lazily" initialize themselves (either via approach you've suggested above or by making appenders themselves "semi" singletons - e.g. appender class has a static instance field which gets populated by afterPropertiesSet() method; that way you can create appender itself as bean within Spring) but it seems somewhat messy and inconsistent.

Another approach is to dynamically reconfigure Log4j once Spring context is initialized; e.g. write a listener to catch a ContextStartedEvent, obtain all beans of type Appender from the context and add them to Log4j configuration. This will also allow you to create your appenders as beans but avoid singleton mess somewhat.

OTHER TIPS

Bit late, but I hope that this can help someone else. I've documented a solution to this issue in the answer i've provided in the following link:

log4j - Accessing spring bean from logging appender class

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top