Spring Boot: LoggingApplicationListener干扰应用服务器日志记录

15

Spring Boot会使用LoggingApplicationListener自动初始化底层日志系统。如果我正在开发的应用程序是独立的或单独运行,这是很好的。

但是我正在开发一个Web应用程序,将部署到WSO2应用服务器中,该服务器提供统一的日志记录(使用log4j),具有诸如运行时集中日志级别管理(通过Web界面)、业务报告等功能。

如果我直接使用Spring Boot,则它会完全自己记录所有内容。我的第一个尝试是删除spring-boot-starter-logging并手动添加slf4j-api作为provided。这在某种程度上起作用,因为LoggingApplicationListener现在覆盖了由WSO2提供的全局logmanager的设置(甚至导致全局appender关闭)。

我想到的唯一“解决方案”就是通过反射删除该侦听器。然后Spring Boot开始像它应该的那样行事(通过全局记录器进行记录,而不是覆盖预定义的日志级别、输出格式、appender等)。

这个“解决方案”看起来像这样:

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

在我的研究和代码分析中,是否有任何更好的解决方案可以解决我的问题,而且可能不那么hacky?


最好的做法是将您的解决方案作为问题的答案编写,以便允许用户对答案进行投票。我已经为您的问题点赞了,但Christophe的解决方案看起来更加简洁。 - jediz
2个回答

8

谢谢您的帖子,非常有帮助。

我在使用Websphere应用服务器时遇到了同样的问题:在Spring Boot上下文初始化后,我再也没有日志了。这个解决方案等效但更加简洁,通过覆盖SpringBootServletInitializer的run方法来实现:

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

我有同样的问题。谢谢。 - NeptuneZ

5
自从Spring Boot 1.4版本以来,LoggingSystem自动配置可以被禁用。
请查看Spring文档中的“Custom Log Configuration”部分:https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html#boot-features-custom-log-configuration 引用如下:
您可以通过使用org.springframework.boot.logging.LoggingSystem系统属性来强制Spring Boot使用特定的日志记录系统。该值应为LoggingSystem实现的完全限定类名。您还可以通过使用none值来完全禁用Spring Boot的日志记录配置。
例如,对于Tomcat,请设置环境变量JAVA_OPTS:
JAVA_OPTS="-Dorg.springframework.boot.logging.LoggingSystem=none"

如果您可以承受指定“JAVA_OPTS”,那么这是最好的方法 - 如果您需要应用程序在开箱即用时以此方式运行,仍然需要覆盖“SpringBootServletInitializer”。 - jediz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接