无法在 logback.xml 中使用 Spring 属性 占位符
Unable to use Spring Property Placeholders in logback.xml
我有一个使用 Logback 的 Spring 引导控制台应用程序。所有属性(对于应用程序和 Logback)都被外部化到类路径中的标准 application.properties 文件中。这些属性可以在应用程序本身中很好地获取,但不会在 logback.xml 文件中获取。似乎 logback.xml 在 Spring 引导启动之前被处理,因此 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 不知道在哪里可以找到它。通过将我的 Spring 相关属性保留在我的外部 application.properties 文件中,将日志记录相关属性移动到应用程序-internal.properties 文件(位于 内部 jar),并将 Logback 指向 that 文件 (<property resource="application-internal.properties" />
) 让一切按预期工作!
${...}
不是 Spring 中的 "Spring EL";它们是 属性 占位符。
我认为您混淆了 logback "variables" 和 Spring "Property Placeholders"。
他们只是碰巧使用相同的语法 ${...}
。
logback 对 Spring 属性 占位符机制一无所知,反之亦然。您需要根据 logback 文档而不是 application.properties
/ application.yml
配置您的 logback 变量,这严格来说是一个 Spring (引导)概念。
编辑:
快速查看 logback 文档后,添加
<property resource="application.properties" />
到 logback.xml
应该可以。
从 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
编辑:感谢安德斯
.........
正如上面的回答,您可以使用 <springProperty>
元素访问 spring 引导属性...但是要记住的是,logback 配置文件必须命名为 logback-spring.xml
, 如果你将文件命名为 logback.xml
(我正在使用 spring-boot 1.3.5.RELEASE
)
则不起作用
上述解决方案主要适用于 bootrap.properties
。但是,在我目前发现的 logback 配置中使用来自远程 Spring 配置服务器的属性的唯一方法是以编程方式应用它们:
@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);
}
}
Here 是一个很好的例子,如何用这种方式使用新的 appender 自定义 logback。
有一种方法可以将 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>
我有一个使用 Logback 的 Spring 引导控制台应用程序。所有属性(对于应用程序和 Logback)都被外部化到类路径中的标准 application.properties 文件中。这些属性可以在应用程序本身中很好地获取,但不会在 logback.xml 文件中获取。似乎 logback.xml 在 Spring 引导启动之前被处理,因此 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 不知道在哪里可以找到它。通过将我的 Spring 相关属性保留在我的外部 application.properties 文件中,将日志记录相关属性移动到应用程序-internal.properties 文件(位于 内部 jar),并将 Logback 指向 that 文件 (<property resource="application-internal.properties" />
) 让一切按预期工作!
${...}
不是 Spring 中的 "Spring EL";它们是 属性 占位符。
我认为您混淆了 logback "variables" 和 Spring "Property Placeholders"。
他们只是碰巧使用相同的语法 ${...}
。
logback 对 Spring 属性 占位符机制一无所知,反之亦然。您需要根据 logback 文档而不是 application.properties
/ application.yml
配置您的 logback 变量,这严格来说是一个 Spring (引导)概念。
编辑:
快速查看 logback 文档后,添加
<property resource="application.properties" />
到 logback.xml
应该可以。
从 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
编辑:感谢安德斯
.........
正如上面的回答,您可以使用 <springProperty>
元素访问 spring 引导属性...但是要记住的是,logback 配置文件必须命名为 logback-spring.xml
, 如果你将文件命名为 logback.xml
(我正在使用 spring-boot 1.3.5.RELEASE
)
上述解决方案主要适用于 bootrap.properties
。但是,在我目前发现的 logback 配置中使用来自远程 Spring 配置服务器的属性的唯一方法是以编程方式应用它们:
@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);
}
}
Here 是一个很好的例子,如何用这种方式使用新的 appender 自定义 logback。
有一种方法可以将 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>