Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot: LoggingApplicationListener interfering with Application Server logging

Spring Boot automatically initializes the underlying logging system using the LoggingApplicationListener. This is a nice thing if the application I'm developing runs isolated or standalone.

However I'm developing a web application that will be deployed into the WSO2 Application Server, which offers unified logging (using log4j), with features like central log level management (at runtime via web interface), business reporting etc.

If I use Spring Boot "as is", it logs everything completely on its own. My first shot was, to remove spring-boot-starter-logging and manually add slf4j-api as provided. This works to some extent, since the LoggingApplicationListener now overrides settings of the global logmanager provided by WSO2 (and even causes global appenders to be closed).

The only "solution" I came up with is to remove the listener via reflection. Then Spring Boot starts to behave exactly as it should (logging via the global logger and not overriding the pre defined log levels, output formats, appenders, etc.)

That "solution" looks like this:

@SpringBootApplication
public class MyApp extends SpringBootServletInitializer {

    public static void main(String... args) {
        SpringApplication.run(MyApp.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        try {
            Field appField = SpringApplicationBuilder.class.getDeclaredField("application");
            appField.setAccessible(true);
            SpringApplication app = (SpringApplication)appField.get(builder);

            Field listenersField = SpringApplication.class.getDeclaredField("listeners");
            listenersField.setAccessible(true);
            List<ApplicationListener<?>> listeners = (List<ApplicationListener<?>>) listenersField.get(app);
            for (int i = listeners.size() - 1; i >= 0; --i) {
                if (listeners.get(i) instanceof LoggingApplicationListener) {
                    listeners.remove(i);
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return builder.sources(MyApp.class);
    }
}

Is there any better solution to my problem that's maybe less hacky which I may have overlooked during my research and code analysis?

like image 298
Andreas Avatar asked Apr 13 '15 16:04

Andreas


2 Answers

thank you for you post it is very helpful. I had the same problem with Websphere Aplication Server: After spring boot context initialized I had no more logs. This solution is equivalent but less dirty by overriding the run method of SpringBootServletInitializer:

@Override
    protected WebApplicationContext run(SpringApplication application) {
        Collection<ApplicationListener<?>> listeners =
                new ArrayList<>();
        for (ApplicationListener<?> listener: application.getListeners()) {
            if (!(listener instanceof LoggingApplicationListener)) {
                listeners.add(listener);
            }
        }
        application.setListeners(listeners);
        return super.run(application);
    }
like image 67
Christophe Rodriguez Avatar answered Sep 16 '22 13:09

Christophe Rodriguez


Since Spring Boot 1.4 the LoggingSystem autoconfiguration can be disabled.

Take a look at the Custom Log Configuration section of the Spring documentation:

You can force Spring Boot to use a particular logging system by using the org.springframework.boot.logging.LoggingSystem system property. The value should be the fully qualified class name of a LoggingSystem implementation. You can also disable Spring Boot’s logging configuration entirely by using a value of none.

For Tomcat, for example, set the environment variable JAVA_OPTS:

JAVA_OPTS="-Dorg.springframework.boot.logging.LoggingSystem=none"
like image 20
tril Avatar answered Sep 17 '22 13:09

tril