【问题标题】:Dynamically change log level for every class in a specific package动态更改特定包中每个类的日志级别
【发布时间】:2018-07-17 15:46:56
【问题描述】:

我正在做一个使用 SLF4J + Logback 的项目,我希望找到一种方法来通过使用 REST API 调用来配置不同范围的日志级别。该调用接收具有范围(类、包或根路径)和所需日志记录级别的对象。我的项目中每个具有记录器的类都使用静态 Logback 记录器。

我使用其他 Stack Overflow 答案和 Logback 手册来找到更改单个类的日志记录级别的解决方案:

LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger target = loggerContext.getLogger(DESIRED_CLASS_PATH);
target.setLevel(DESIRED_LOGGING_LEVEL);

这适用于该课程。但是,我尝试使用根记录器来更改项目中所有类的所有记录器,使用以下方法:

Logger rootLogger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
rootLogger.setLevel(DESIRED_LOGGING_LEVEL);

这只会更改根记录器,当我尝试打印项目内任何类的日志级别时,它不是所需的日志级别。我尝试在声明包记录器(包含我的所有类和子包的包)的 logback.xml 文件中声明一个记录器,并尝试修改它以更改子类记录器,但这不起作用。这是我的 logback.xml 文件:

<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern>
        </layout>
    </appender>

    <root level="info">
        <appender-ref ref="STDOUT"/>
    </root>

    <logger name="my.uppermost.package" level="info" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>
</configuration>

我是否误解了 Logback 的代码或功能?如果没有,有没有一种方法可以输入我的 REST API 调用的包路径并更新该包中包含的类的所有记录器?

【问题讨论】:

    标签: java logging logback slf4j


    【解决方案1】:

    您可以获取现有记录器的列表并按名称过滤它们:

    LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
    
    for(logger : loggerContext.getLoggerList()) {
     if(logger.getName().startWith("my.target.package.")) {
      logger.setLevel(DESIRED_LOGGING_LEVEL);
     }
    }
    

    请注意,它只会更改已经存在的 logger 的日志级别。如果 my.target.package 中的某个对象稍后注册了一个 logger,它的日志级别将是 logback.xml 中配置的任何内容

    【讨论】:

      【解决方案2】:

      这只会更改根记录器,当我尝试打印项目内任何类的日志级别时,它不是所需的日志级别

      请注意Logger#getEffectiveLevel,而不是Logger#getLevel 是用于过滤日志的实际级别。


      参考Effective Level aka Level Inheritance:

      如果给定的记录器没有被分配一个级别,那么它会从它最近的祖先那里继承一个具有分配级别的记录器。更正式地说:

      给定记录器 L 的有效级别等于其层次结构中的第一个非空级别,从 L 本身开始并在层次结构中向上移动到根记录器。

      参考LoggersetLevelhandleParentLevelChange的源码,如果没有设置这些logger的日志级别,调用package logger的setLevel会设置内部logger的“Effective Level”。 如果这些记录器中已经设置了日志级别,Thibault Urien's answer 将完成这项工作。

      上面的行为可以通过下面的例子来说明。 LoggerLevelNotSet 没有设置记录器级别的类

      package com.logback.logger;
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      public class LoggerLevelNotSet {
          private static final Logger logger = LoggerFactory.getLogger(LoggerLevelNotSet.class);
      
          public static void log() {
              logger.trace("TRACE");
              logger.debug("DEBUG");
              logger.info("TRACE");
              logger.warn("WARN");
              logger.error("ERROR");
          }
      }
      

      LoggerLevelNotSet 设置了记录器级别的类

      package com.logback.logger;
      
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      public class LoggerLevelSet {
          private static final Logger logger = LoggerFactory.getLogger(LoggerLevelSet.class);
      
          public static void log() {
              logger.trace("TRACE");
              logger.debug("DEBUG");
              logger.info("TRACE");
              logger.warn("WARN");
              logger.error("ERROR");
          }
      }
      

      logback.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <configuration scan="true" scanPeriod="30 seconds">
      
          <appender name="stdout"
                    class="ch.qos.logback.core.ConsoleAppender">
              <layout class="ch.qos.logback.classic.PatternLayout">
                  <Pattern>%-5level %logger{36} - %msg%n</Pattern>
              </layout>
          </appender>
      
          <logger name="com.logback.logger"
                  additivity="false" level="TRACE">
              <appender-ref ref="stdout"/>
          </logger>
          <logger name="com.logback.logger.LoggerLevelSet"
                  additivity="false" level="WARN">
              <appender-ref ref="stdout"/>
          </logger>
      
          <root>
              <appender-ref ref="stdout"/>
          </root>
      </configuration>
      

      TestSetLoggerLevel主类

      package com.logback.logger;
      
      import ch.qos.logback.classic.Level;
      import ch.qos.logback.classic.LoggerContext;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      
      public class TestSetLoggerLevel {
          private static final Logger logger = LoggerFactory.getLogger(TestSetLoggerLevel.class);
      
          public static void main(String[] args) {
              LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
              logger.error("Before set level");
              logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelNotSet"));
              logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelSet"));
              LoggerLevelNotSet.log();
              LoggerLevelSet.log();
              loggerContext.getLogger("com.logback.logger").setLevel(Level.ERROR);
              logger.error("After set level");
              logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelNotSet"));
              logLevel(loggerContext.getLogger("com.logback.logger.LoggerLevelSet"));
              LoggerLevelNotSet.log();
              LoggerLevelSet.log();
          }
      
          private static void logLevel(ch.qos.logback.classic.Logger log) {
              logger.error("{} level: {} effective level:{}", log.getName(), log.getLevel(), log.getEffectiveLevel());
          }
      }
      

      结果

      ERROR c.logback.logger.TestSetLoggerLevel - Before set level
      ERROR c.logback.logger.TestSetLoggerLevel - com.logback.logger.LoggerLevelNotSet level: null effective level:TRACE
      ERROR c.logback.logger.TestSetLoggerLevel - com.logback.logger.LoggerLevelSet level: WARN effective level:WARN
      TRACE com.logback.logger.LoggerLevelNotSet - TRACE
      DEBUG com.logback.logger.LoggerLevelNotSet - DEBUG
      INFO  com.logback.logger.LoggerLevelNotSet - TRACE
      WARN  com.logback.logger.LoggerLevelNotSet - WARN
      ERROR com.logback.logger.LoggerLevelNotSet - ERROR
      WARN  com.logback.logger.LoggerLevelSet - WARN
      ERROR com.logback.logger.LoggerLevelSet - ERROR
      ERROR c.logback.logger.TestSetLoggerLevel - After set level
      ERROR c.logback.logger.TestSetLoggerLevel - com.logback.logger.LoggerLevelNotSet level: null effective level:ERROR
      ERROR c.logback.logger.TestSetLoggerLevel - com.logback.logger.LoggerLevelSet level: WARN effective level:WARN
      ERROR com.logback.logger.LoggerLevelNotSet - ERROR
      WARN  com.logback.logger.LoggerLevelSet - WARN
      ERROR com.logback.logger.LoggerLevelSet - ERROR
      

      【讨论】:

        猜你喜欢
        • 2018-04-14
        • 1970-01-01
        • 2016-07-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-03
        • 1970-01-01
        • 2012-11-06
        相关资源
        最近更新 更多