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

45

我有一个使用Logback的Spring Boot控制台应用程序。所有属性(包括应用程序和Logback的属性)都外部化到类路径下的标准application.properties文件中。这些属性在应用程序本身中很好地被接受,但在logback.xml文件中没有被接受。似乎logback.xml在Spring Boot启动之前被处理,因此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负责为我解析这些变量。 我确实有< strong>元素,但那让我思考。

我的application.properties文件在jar外部,因此Logback不知道在哪里找到它。通过将与Spring相关的属性保留在我的外部application.properties文件中,将日志记录相关属性移动到位于内部的application-internal.properties文件中,并将Logback指向<property resource="application-internal.properties" />文件,使一切都按预期工作!

5个回答

86

自从Spring Boot 1.3版本以来,您可以更好地将Spring属性添加到logback-spring.xml配置文件中:

现在,您只需添加一个“springProperty”元素即可。
属性name指的是logback属性,而属性source则指的是Spring属性。

<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

编辑:感谢Anders

.........


1
有没有 logback-spring.groovy 的等效版本呢 ^^? - Matthew Payne
1
这个东西的文档在哪里? - sashok_bg
2
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html - oborovyk
@MatthewPayne,你有没有找到在Groovy中如何做到这一点的方法? - WendyG
这不是一个百分之百可靠的解决方案。如果你通过包含外部文件来外部化你的logback-spring.xml文件,然后将"maxSize"从100MB更改为2KB,你会看到文件被创建为destination_IS_UNDEFINED.log。这是因为正如@Gary Russell在他的答案中所解释的那样。 - raikumardipak

45

${...} 在 Spring 中不是 "Spring EL",而是属性占位符。

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

它们只是恰好使用相同的语法 ${...}

logback 不知道 Spring 属性占位符机制,反之亦然。您需要根据 logback 文档配置 logback 变量,而不是在 application.properties/application.yml 中进行配置,这严格来说是一个 Spring(boot)概念。

编辑:

经过快速查看 logback 文档,添加

<property resource="application.properties" />

应该可以将logback.xml文件添加到配置中。


5
这是指向“logback文档”的链接:http://logback.qos.ch/manual/configuration.html#variableSubstitution - SunshinyDoyle
@Gary,我想要可配置的文件模式扩展。这个可能吗?或者我想用外部的logback.xml覆盖内部的logback.xml。这个可能吗? - parita porwal
对于一个外部文件(不在类路径中,但在文件系统中可用): <property file="environment.properties" /> - Jean-Christophe
感谢您提供缺失的神秘代码(属性资源)。顺便提一下: "application.yml" 也可以使用... 此处有我记录的文档链接: https://stackoverflow.com/questions/33186668/spring-boot-logback-db-appender-properties/54288986#54288986 - granadaCoder

9

如上所述,您可以使用<springProperty>元素访问Spring Boot属性...但需要记住的是,logback配置文件必须命名为logback-spring.xml,如果将文件命名为logback.xml则无法正常工作(我正在使用spring-boot 1.3.5.RELEASE)。


1
使用 logback-dev.xmllogback-prod.xml 配合 spring-boot 1.3.3.RELEASE 对我来说是有效的。 - sdl
如果仍然无法工作,请检查应用程序配置名称,它应该是application.properties,或者您为应用程序指定的任何名称。在这种情况下,似乎额外的@PropertySource-es不起作用。 - Daniel Hári
1
还有一件事需要记住:至少对我来说,在将application.properties重命名为bootstrap.properties之前,它是无法正常工作的。 - lubumbax

2

以上解决方案大多适用于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。


0

有一种方法可以将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>

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