有没有办法阻止 Spring Boot 覆盖我的日志配置?

Is there anyway to stop Spring Boot from overwriting my log config?

我有一个具有以下属性的记录器:

PrivateConfig [loggerConfig=Special, config=org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration@709a148, loggerConfigLevel=INFO, intLevel=400, logger=Special.com:INFO in 73d16e93]

这是一个特殊的记录器,具有我的应用程序所需的特定格式和特定​​目的地

此特殊记录器是通过以下方式创建的:

        Level level = Level.toLevel(logLevel);

        ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();
        builder.setStatusLevel(level);
        builder.setConfigurationName("whatever");

        LoggerComponentBuilder specialLogger = builder.newLogger("Special", level);
        AppenderComponentBuilder specialAppenderBuilder =  builder
                    .newAppender("Special", "RollingFile")
                    .otherComponents();
        specialAppenderBuilder.add(
              builder
                    .newLayout("PatternLayout")
                    .otherComponents();
        builder.add(specialAppenderBuilder);
        specialLogger = specialLogger
              .add(builder.newAppenderRef("Special"))
              .addAttribute("additivity", false);
        builder.add(specialLogger);

        LoggerContext ctx = Configurator.initialize(builder.build());
        ctx.start();

此记录器在未使用 Spring Boot

的应用程序 A 中工作

我将应用程序 A 的一部分导入到应用程序 B,它是 Spring 基于引导的,但随后完全相同的记录器变为:

PrivateConfig [loggerConfig=root, config=XmlConfiguration[location=jar:file:/Users/stamaki/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot/2.4.4/38392ae406009e55efe873baee4633bfa6b766b3/spring-boot-2.4.4.jar!/org/springframework/boot/logging/log4j2/log4j2.xml], loggerConfigLevel=INFO, intLevel=400, logger=Special.com:INFO in 18b4aac2]

请注意,记录器配置正在从 Special 覆盖到 root,它不再遵循我编写的自定义 BuiltConfiguration,而是使用 Springboot 内部 xml.

如何阻止 Spring 引导覆盖我的配置?

似乎有一个类似的问题: 但解决方案不起作用

我也试过 Spring Boot: LoggingApplicationListener interfering with Application Server logging 但他们的解决方案仍然对我不起作用,因为它将我的记录器更改为

PrivateConfig [loggerConfig=root, config=org.springframework.boot.logging.log4j2.SpringBootConfigurationFactory$SpringBootConfiguration@16a3cc88, loggerConfigLevel=ERROR, intLevel=200, logger=NonSensitive.com.textiq.precisionenhancer.service.PrecisionEnhancerBackendService:ERROR in 18b4aac2]

即仍然使用 Root Config,而不是我设置的 Special Config,唯一与上面不同的是这是默认的 Root Logger 配置。

请不要提出“更新 XML 以使其具有相同格式”之类的建议,这不够模块化。我只是想使用我的库创建的同一个记录器,而不会被 Spring Boot.

覆盖

弄清楚发生了什么。

        LoggerContext ctx = Configurator.initialize(builder.build());
        ctx.start();

在应用A和B中,builder.build()都有正确的信息,但是应用B的ctx没有自定义配置

调查 Configurator.initalize,这会尝试触发 Log4jContextFactory:

    public LoggerContext getContext(final String fqcn, final ClassLoader loader, final Object externalContext,
            final boolean currentContext, final Configuration configuration) {
        final LoggerContext ctx = selector.getContext(fqcn, loader, currentContext, null);
        if (externalContext != null && ctx.getExternalContext() == null) {
            ctx.setExternalContext(externalContext);
        }
        if (ctx.getState() == LifeCycle.State.INITIALIZED) {
            ContextAnchor.THREAD_CONTEXT.set(ctx);
            try {
                ctx.start(configuration);
            } finally {
                ContextAnchor.THREAD_CONTEXT.remove();
            }
        }
        return ctx;
    }

请注意,除非上下文当前具有状态 INITIALIZED

,否则不会使用 configuration

可能是因为Spring会以任何一种方式在内部初始化某种Log4j,即使你设置了-Dorg.springframework.boot.logging.LoggingSystem=none,返回的ctx总是STARTED.

它的破解方法是始终调用 reinitailize 以强制将配置更新为内部的任何内容 builder.build():

        BuiltConfiguration configuration = builder.build();
        LoggerContext ctx = Configurator.initialize(configuration);
        ctx.reconfigure(configuration);
        ctx.start();