无法在 logback.xml 中使用 Spring 属性占位符

IT小君   2021-10-26T01:15:36

我有一个使用 Logback 的 Spring Boot 控制台应用程序。所有属性(对于应用程序以及 Logback)都被外部化到类路径中的标准 application.properties 文件中。这些属性可以在应用程序本身中很好地获取,但不会在 logback.xml 文件中获取。看起来好像在 Spring Boot 启动之前处理了 logback.xml,因此不处理 EL 占位符。

以 FileNamePattern 为例,在 application.properties 中,我有这样的内容:

log.filePattern=/%d{yyyy/MM-MMMM/dd-EEEE}

在 logback.xml 中,我会有这个:

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <FileNamePattern>${log.logDirectory}${log.filePattern}.log
    </FileNamePattern>
</rollingPolicy>

运行应用程序时,我会看到如下错误:

ERROR in ch.qos.logback.core.joran.spi.Interpreter@24:25 - 
RuntimeException in Action for tag [rollingPolicy]
java.lang.IllegalStateException: FileNamePattern
[log.logDirectory_IS_UNDEFINEDlog.filePattern_IS_UNDEFINED.log]
does not contain a valid DateToken

类似的代码在其他 Spring(不是 Spring Boot)应用程序中工作得很好,所以我很好奇 Spring Boot 的行为是否有点不同。

解决方案:

感谢@Gary 的回复!很高兴知道 Spring EL 和 Logback 的变量之间的区别......我以为是 Spring 负责为我解析这些变量。确实有这个元素,但这让我开始思考。

我的 application.properties 文件在 jar 之外,所以 Logback 不知道在哪里可以找到它。通过保持我的春节,相关性在我的外部application.properties文件,移动测井相关性为application-internal.properties文件(位于里面的罐子),并指向的logback到文件(<property resource="application-internal.properties" />)得到的一切工作正常!

评论(5)
IT小君

从 Spring Boot 1.3 开始,您可以更好地将 spring 属性放入 logback-spring.xml 配置中:

现在您可以添加一个“springProperty”元素。

<springProperty name="destination" source="my.loggger.extradest"/>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${destination}</file>
        ...
    </file>
</appender>

https://github.com/spring-projects/spring-boot/commit/055ace37f006120b0006956b03c7f358d5f3729f

编辑:感谢安德斯

…………

2021-10-26T01:15:36   回复
IT小君

${...}不是 Spring 中的“Spring EL”;它们是属性占位符。

我认为您将 logback“变量”与 Spring“属性占位符”混淆了。

他们只是碰巧使用相同的语法${...}

logback 对 Spring 属性占位符机制一无所知,反之亦然。您需要根据 logback 文档配置您的 logback 变量,而不是在application.properties/application.yml这严格是一个 Spring(引导)概念中。

编辑:

快速查看 logback 文档后,添加

<property resource="application.properties" />

logback.xml应该工作。

2021-10-26T01:15:36   回复
IT小君

如上所述,您可以使用<springProperty>元素访问 spring boot 属性...但要记住的一点是必须命名 logback 配置文件logback-spring.xml,如果您命名文件则不起作用logback.xml(我正在使用spring-boot 1.3.5.RELEASE

2021-10-26T01:15:37   回复
IT小君

上述解决方案主要适用于bootrap.properties. 但是,在我目前找到的 logback 配置中使用来自远程 Spring Config Server 的属性的唯一方法是以编程方式应用它们:

@Component
public class LoggerConfiguration implements ApplicationListener<EnvironmentChangeEvent> {

    @Autowired protected Environment environment;

    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        // enviroment here has already loaded all properties and you may alter logback config programatically
        ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
    }


}

是一个很好的示例,如何以这种方式使用新的 appender 自定义 logback。

2021-10-26T01:15:37   回复
IT小君

有一种方法可以将 Spring 属性映射到 Logback 属性并在条件中使用它们:

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="ACTIVE_PROFILE" source="spring.profiles.active"/>
<!--   defined in the application-prod.properties/>-->
<springProperty scope="context" name="SPRING_WRITER_DISABLED" source="writer.disabled"/>
<property name="LOGBACK_WRITER_DISABLED" value="${SPRING_WRITER_DISABLED}"/>

<if condition='property("LOGBACK_WRITER_DISABLED").equals("false")'>
    <then>
        <appender name="testappender" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${ACTIVE_PROFILE}/${HOSTNAME}/testappender.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <fileNamePattern>
                    {ACTIVE_PROFILE}/${HOSTNAME}/testappender-%d{yyyy-MM-dd}.%i.log
                </fileNamePattern>
                <maxFileSize>300MB</maxFileSize>
                <maxHistory>3</maxHistory>
                <totalSizeCap>1GB</totalSizeCap>
            </rollingPolicy>
            <encoder>
                <pattern>%msg%n</pattern>
            </encoder>
        </appender>
        <logger name="testappender" level="INFO" additivity="false">
            <appender-ref ref="testappender"/>
        </logger>
    </then>
</if>
</configuration>
2021-10-26T01:15:37   回复