通过环境变量在 Spring Boot 中设置日志记录级别

Posted

技术标签:

【中文标题】通过环境变量在 Spring Boot 中设置日志记录级别【英文标题】:Set Logging Level in Spring Boot via Environment Variable 【发布时间】:2016-03-14 20:39:47 【问题描述】:

是否可以在 Spring Boot 应用程序中单独通过环境变量设置日志记录级别?

我不想使用 application.properties,因为我在 Cloud Foundry 上运行,并且想在不部署的情况下获取更改(但在应用重新启动之后,或者更准确地说是重新暂存之后)。

我试过设置像LOGGING_LEVEL_ORG_SPRINGFRAMEWORK=TRACE 这样的环境变量,但这没有效果。将logging.level.org.springframework: TRACE 放入application.properties 确实有效。

【问题讨论】:

问题中提出的两种方法在Relaxed Binding的基础上应该是等价的。可能当时 Spring Boot 有 bug(版本未指定)。 也许 OP 更改了示例值以简化问题描述,从而无意中篡改了问题。请注意,通过环境变量设置日志级别仅适用于包,但不适用于类!有关详细信息,请参阅下面的答案。 【参考方案1】:

这只是一个想法,但你有没有尝试设置

_JAVA_OPTIONS=-Dlogging.level.org.springframework=TRACE?

理论上,这种方式 -Dlogging.level.org.springframework=TRACE 将作为默认 JVM 参数传递,并且应该影响您环境中的每个 JVM 实例。

【讨论】:

可以在实践中确认:我检查了sample-logback 项目(使用版本1.3.0.RELEASE)并运行mvn spring-boot:run -Dlogging.level.org.springframework=TRACE,它产生了大量的日志输出。使用全部大写 -DLOGGING_LEVEL_ORG_SPRINGFRAMEWORK=TRACE 或其变体没有任何作用。 如果-D... 参数有效,那么设置_JAVA_OPTIONS 环境变量应该真的有效! mvn 命令就像任何 java 一样拾取它们。但是请注意开头的下划线,这是必要的。有关更多信息,请参阅***.com/questions/17781405。 我会试一试 - 这将通过 Cloud Foundry Java Buildpack 运行,但希望它会尊重并传递 _JAVA_OPTIONS 中的值 我不熟悉 Java Buildpack,但他们有一个关于如何使用另一个环境变量的文档,JAVA_OPTS:github.com/cloudfoundry/java-buildpack/blob/master/docs/… 我会建议 JAVA_TOOL_OPTIONS 而不是 _JAVA_OPTIONS,如下所述:bugs.openjdk.java.net/browse/JDK-4971166【参考方案2】:

通过环境变量设置日志级别只能用于包,不能用于类

我遇到了和 OP 一样的问题。我想知道为什么这里的一些用户报告所提出的解决方案效果很好,而其他人则回答他们没有。 我在 Spring Boot 2.1 上,问题在过去几年明显有所改变,但目前的情况如下:

TL;DR

设置包的日志级别有效

LOGGING_LEVEL_COM_ACME_PACKAGE=DEBUG

虽然为特定的类设置日志级别无效

LOGGING_LEVEL_COM_ACME_PACKAGE_CLASS=DEBUG

怎么可能?

看看 Spring Boot 的 LoggingApplicationListener。 如果您调试它并在突出显示的代码块中设置断点,您会看到类 com.acme.mypackage.MyClass 的日志级别定义变为 com.acme.mypackage.myclass. 因此类的日志级别定义看起来与包的日志级别定义完全相同。

这与 Spring 的 Relaxed Binding 有关,它为环境变量提出了大写符号。因此类的典型驼峰式表示法对于 LoggingApplicationListener 是不可见的:MyClass 的环境变量必须定义为 MYCLASS,并且在 Spring 的 Environment 中将作为 myclass 提供(此示例忽略类的完全限定名称)

一旦类的驼峰式表示法丢失,在运行期间就没有机会恢复原来的类名。 因此,环境变量中的日志定义不适用于类,而仅适用于包。

【讨论】:

这在 Spring Boot 2.1.2 上让我丧命,文档中没有提到这个限制。目前,如果我们想调试单个类,我们的技巧是重新部署特殊的 .jar,并在 application.properties 中启用调试日志记录。感谢您的详细分析 现在文档中也承认了这一点:docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/… 说“上述方法仅适用于包级别的日志记录。由于宽松绑定总是将环境变量转换为小写,因此无法配置日志记录以这种方式单独的类。如果需要为类配置日志记录,可以使用 SPRING_APPLICATION_JSON 变量。"【参考方案3】:

我也尝试通过环境变量设置日志记录级别,但如前所述,使用大写名称的环境变量是不可能的,例如。 LOGGING_LEVEL_ORG_SPRINGFRAMEWORK=DEBUG。我也不想通过application.properties_JAVA_OPTIONS 这样做。

在深入了解org.springframework.boot.logging.LoggingApplicationListener 类之后,我检查了 Spring Boot 是否尝试将日志记录级别 DEBUG 设置为 ORG_SPRINGFRAMEWORK 包,这不是真正的包名。所以结论是您可以使用环境变量来设置日志记录级别,但它需要采用以下形式: LOGGING_LEVEL_org.springframework=DEBUG 要么 logging.level.org.springframework=DEBUG

在 spring boot 1.5.3 上测试

【讨论】:

我在 AWS 上使用 Spring Boot 1.3.8 进行了尝试,但不幸的是它没有工作。【参考方案4】:

是的,您可以使用环境变量控制日志记录级别。这是我在 Cloud Foundry 平台上部署的 Spring Boot 应用程序的实现方式。

在您的日志配置文件中,为日志级别提供占位符以从环境变量中读取值。默认为 INFO。

    <logger name="com.mycompany.apps.cf" level="$APP_LOGGING_LEVEL:-INFO">
      <appender-ref ref="CONSOLE"/>
    </logger>

然后,在 CF 部署清单文件中提供环境变量。

应用: - 名称:我的应用程序名称 内存:2048 环境: APP_LOGGING_LEVEL:调试

我希望这会有所帮助。

【讨论】:

如果你在本地运行应用,使用-DAPP_LOGGING_LEVEL=DEBUG 我确实做了类似的解决方法,但这意味着必须知道您希望在设计时能够控制哪些记录器,这是相当有限的。【参考方案5】:

从 Spring Boot 2.0.x 开始,这又可以工作了。使用 Spring Boot v2.0.9.RELEASE 测试。例如。启用连接池调试日志:

LOGGING_LEVEL_COM_ZAXXER=DEBUG java -jar myApp.jar

或Spring框架调试日志:

LOGGING_LEVEL_ORG_SPRINGFRAMEWORK=DEBUG java -jar myApp.jar

或两者兼有:

LOGGING_LEVEL_ORG_SPRINGFRAMEWORK=DEBUG LOGGING_LEVEL_COM_ZAXXER=DEBUG java -jar myApp.jar

有关更多应用程序属性,请参阅"Application Poperties" in Spring Boot Reference Documentation。

【讨论】:

更新链接:docs.spring.io/spring-boot/docs/current/reference/html/…【参考方案6】:

同样在 Cloud Foundry 中使用 Spring Boot (v1.2.3),我发现可以使用如下环境变量调整根日志记录级别:

$ cf set-env <app name> LOGGING_LEVEL_ROOT DEBUG

不幸的是,似乎无法调低特定包的日志记录级别(至少在我使用的 Java Buildpack 和 Spring Boot 版本中)。例如在上述之外添加以下内容不会降低 Spring 框架的日志级别:

$ cf set-env <app name> LOGGING_LEVEL_ORG_SPRINGFRAMEWORK INFO

如果您使用 Splunk 之类的工具来收集日志,则可以过滤掉噪音。

另一种看起来很有前途的替代方案可能是基于构建包参数选项的自定义(请参阅here):

$ cf set-env <app name> 'arguments: "-logging.level.root=DEBUG -logging.level.org.springframework=INFO"'

遗憾的是,我无法让它真正发挥作用。我当然同意能够在包级别重新配置日志记录级别而不更改应用程序代码会很方便开始工作。

【讨论】:

【参考方案7】:

我还是建议你使用 Spring 配置文件:

    创建 2 个属性文件:

    application-local.propertiesapplication-remote.properties

    (个人资料名称可能明显不同)

    在每个文件中相应地设置日志记录级别 (logging.level.org.springframework)

    在本地使用-Dspring.profiles.active=local 运行您的应用程序,在CF 上使用-Dspring.profiles.active=remote

【讨论】:

谢谢。遗憾的是,这需要在设计时而不是运行时知道我想要增加详细程度的事情。【参考方案8】:

在 spring-boot 2.0.0 中,添加 --trace 有效。 例如java -jar myapp.jar --debugjava -jar myapp.jar --trace

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html#boot-features-logging-console-output

【讨论】:

【参考方案9】:

这是一个使用Logback 和Janino 的示例,通过properties or environmental variables 有条件地包含不同的日志配置...基本配置,logback.xml 正在使用条件来进行开发控制台日志记录或生产文件日志记录...只需删除/resources/中的以下文件


logback.xml


<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
    <if condition='property("spring.profiles.active").contains("dev")'>
        <then>
            <include resource="org/springframework/boot/logging/logback/base.xml"/>
            <include resource="dev.xml" optional="true"/>
        </then>
    </if>
    <if condition='property("spring.profiles.active").contains("pro")'>
        <then>
            <include resource="org/springframework/boot/logging/logback/base.xml"/>
            <include resource="pro.xml" optional="true"/>
        </then>
    </if>
</configuration>

dev.xml

<included>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <charset>utf-8</charset>
            <Pattern>%-30([%p] [%c:%L]) » %m%n%rEx</Pattern>
        </encoder>
    </appender>

    <!-- CHATTY LOGGERS HERE.-->
    <logger name="org.springframework" level="DEBUG"/>

    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
        <resetJUL>true</resetJUL>
    </contextListener>

    <root level="$logback.loglevel">
        <appender-ref ref="CONSOLE"/>
    </root>

</included>

pro.xml

<included>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <property name="FILE_LOG_PATTERN"
              value="%dyyyy-MM-dd HH:mm:ss.SSS %5p $PID:-  --- [%t] %-40.40logger39 : %m%n%wex"/>
    <property name="FILE_NAME_PATTERN" value="./logs/%dyyyy-MM-dd-exec.log"/>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>FILE_NAME_PATTERN</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>$FILE_LOG_PATTERN</pattern>
        </encoder>
    </appender>

    <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
        <queueSize>512</queueSize>
        <appender-ref ref="FILE"/>
    </appender>

    <!-- APP SPECIFIC LOGGERS HERE.-->
    <logger name="org.springframework.boot.SpringApplication" level="INFO"/>

    <root level="INFO">
        <appender-ref ref="FILE"/>
    </root>

</included>

【讨论】:

【参考方案10】:

任何人都可以解释为什么这不起作用?

$ export LOGGING_LEVEL_COM_ACME=ERROR

对于使用环境变量作为替代的所有其他配置似乎没有问题,例如:

$ export EUREKA_CLIENT_ENABLED=false

谢谢。

【讨论】:

因为 Spring Boot 不使用环境变量来确定日志级别。它可以使用 JVM 系统属性(由 -Dlogging.level.blah=foo 指定),但在处理日志配置之前,它似乎不会作为潜在的属性值合并到环境变量中。 事实上,它确实有效!也许你有一个错字,或者一个隐藏的空格字符,等等。 LOGGING_LEVEL_COM_ZAXXER=DEBUG java -jar myApp.jar 提高了属于 Hikari 连接池的类的日志级别。使用 Spring Boot v2.0.9.RELEASE 测试。

以上是关于通过环境变量在 Spring Boot 中设置日志记录级别的主要内容,如果未能解决你的问题,请参考以下文章

在 Gradle Spring Boot Hibernate 项目中设置 LiquiBase

spring-boot骆驼案例嵌套属性作为环境变量

如何通过环境变量设置名称中带有下划线的 Spring Boot 属性?

如何通过环境变量设置名称中带有下划线的 Spring Boot 属性?

如何在spring boot中设置禁用浏览器缓存?

如何在 Spring 测试中设置环境变量或系统属性?