15

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?

rajadilipkolli
  • 3,475
  • 2
  • 26
  • 49
Andreas
  • 151
  • 1
  • 3
  • It would have bean cleaner to write your solution as an answer to your question in order to allow users vote on the answers. I'm upvoting your question, but Christophe's solution looks much cleaner. – jediz Apr 18 '18 at 11:47

2 Answers2

8

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);
    }
5

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"
sloth
  • 99,095
  • 21
  • 171
  • 219
tril
  • 96
  • 1
  • 2
  • if you can afford specifying the `JAVA_OPTS` then this is the way to go - If you need the app to behave this way out of the box you still need to override the `SpringBootServletInitializer` – jediz Apr 18 '18 at 11:49