【问题标题】:How to change root logging level programmatically for logback如何以编程方式更改 root 日志记录级别以进行 logback
【发布时间】:2011-04-19 18:19:53
【问题描述】:

我有以下 logback.xml 文件:

<configuration debug="true"> 

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

<root level="debug">
  <appender-ref ref="STDOUT" />
</root>
</configuration>

现在,在发生特定事件时,我想以编程方式将根记录器的级别从 debug 更改为 error。我不能使用变量替换,我必须在代码中这样做。

怎么做?谢谢。

【问题讨论】:

    标签: java logging logback


    【解决方案1】:

    试试这个:

    import org.slf4j.LoggerFactory;
    import ch.qos.logback.classic.Level;
    import ch.qos.logback.classic.Logger;
    
    Logger root = (Logger)LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);
    root.setLevel(Level.INFO);
    

    请注意,您还可以告诉 logback 定期扫描您的配置文件,如下所示:

    <configuration scan="true" scanPeriod="30 seconds" > 
      ...
    </configuration> 
    

    【讨论】:

    • 需要注意的是,slf4j 的目的是抽象出日志框架,但是第一种方法通过直接引用日志框架来消除它。
    • 如果你这样做并得到一个 ClassCastException,很可能是由于类路径上有多个 SLF4J 绑定。日志输出将指出这一点以及存在哪些绑定,以便您确定需要排除哪些绑定。
    • Slf4j 提供了一个 API,以便库可以使用应用程序开发人员想要的任何日志框架记录应用程序日志。关键是应用程序开发人员仍然必须选择一个日志框架,依赖它并配置它。像 dogbane 一样配置记录器并不违反这个原则。
    • @JohnWiseman 如果你想配置它,那么你必须配置它somewhere。由于 slf4j 在这方面没有提供任何东西,总会有一些依赖于底层记录器的东西。无论是一段代码还是一个配置文件。 +++ 如果它应该按照 OP 的要求以编程方式完成,那么你别无选择。尽管如此,优势仍然存在: 1. 只有一小部分代码依赖于具体的记录器引擎(并且可以编写它以便它可以处理不同的实现)。 2. 您也可以配置使用其他记录器编写的库。
    • 为什么对于像日志记录这样的东西来说必须如此复杂,不应该有直接的方法来更改代码本身的日志记录级别。遵循特定库的原则如何优先于其简单性?来自 Python 世界,我不明白为什么像 Logging 这样简单的东西在 Java/Scala 中如此复杂。
    【解决方案2】:

    我假设您正在使用 logback(来自配置文件)。

    来自logback manual,我知道了

    Logger rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME);

    也许这可以帮助您更改值?

    【讨论】:

      【解决方案3】:

      使用 logback 1.1.3 我必须执行以下操作(Scala 代码):

      import ch.qos.logback.classic.Logger
      import org.slf4j.LoggerFactory    
      ...
      val root: Logger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME).asInstanceOf[Logger]
      

      【讨论】:

        【解决方案4】:

        正如其他人所指出的,您只需创建mockAppender,然后创建一个LoggingEvent 实例,该实例基本上侦听在mockAppender 中注册/发生的日志事件。

        这是它在测试中的样子:

        import org.slf4j.LoggerFactory;
        import ch.qos.logback.classic.Level;
        import ch.qos.logback.classic.Logger;
        import ch.qos.logback.classic.spi.ILoggingEvent;
        import ch.qos.logback.classic.spi.LoggingEvent;
        import ch.qos.logback.core.Appender;
        
        @RunWith(MockitoJUnitRunner.class)
        public class TestLogEvent {
        
        // your Logger
        private Logger log = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
        
        // here we mock the appender
        @Mock
        private Appender<ILoggingEvent> mockAppender;
        
        // Captor is generic-ised with ch.qos.logback.classic.spi.LoggingEvent
        @Captor
        private ArgumentCaptor<LoggingEvent> captorLoggingEvent;
        
        /**
         * set up the test, runs before each test
         */
        @Before
        public void setUp() {
            log.addAppender(mockAppender);
        }
        
        /**
         * Always have this teardown otherwise we can stuff up our expectations. 
         * Besides, it's good coding practise
         */
        @After
        public void teardown() {
            log.detachAppender(mockAppender);
        }
        
        
        // Assuming this is your method
        public void yourMethod() {
            log.info("hello world");
        }
        
        @Test
        public void testYourLoggingEvent() {
        
            //invoke your method
            yourMethod();
        
            // now verify our logging interaction
            // essentially appending the event to mockAppender
            verify(mockAppender, times(1)).doAppend(captorLoggingEvent.capture());
        
            // Having a generic captor means we don't need to cast
            final LoggingEvent loggingEvent = captorLoggingEvent.getValue();
        
            // verify that info log level is called
            assertThat(loggingEvent.getLevel(), is(Level.INFO));
        
            // Check the message being logged is correct
            assertThat(loggingEvent.getFormattedMessage(), containsString("hello world"));
        }
        }
        

        【讨论】:

          【解决方案5】:

          我认为您可以使用 MDC 以编程方式更改日志记录级别。下面的代码是更改当前线程的日志记录级别的示例。这种方法不会创建对 logback 实现的依赖(SLF4J API 包含 MDC)。

          <configuration>
            <turboFilter class="ch.qos.logback.classic.turbo.DynamicThresholdFilter">
              <Key>LOG_LEVEL</Key>
              <DefaultThreshold>DEBUG</DefaultThreshold>
              <MDCValueLevelPair>
                <value>TRACE</value>
                <level>TRACE</level>
              </MDCValueLevelPair>
              <MDCValueLevelPair>
                <value>DEBUG</value>
                <level>DEBUG</level>
              </MDCValueLevelPair>
              <MDCValueLevelPair>
                <value>INFO</value>
                <level>INFO</level>
              </MDCValueLevelPair>
              <MDCValueLevelPair>
                <value>WARN</value>
                <level>WARN</level>
              </MDCValueLevelPair>
              <MDCValueLevelPair>
                <value>ERROR</value>
                <level>ERROR</level>
              </MDCValueLevelPair>
            </turboFilter>
            ......
          </configuration>
          
          MDC.put("LOG_LEVEL", "INFO");
          

          【讨论】:

            【解决方案6】:

            我好像成功了

            org.jboss.logmanager.Logger logger = org.jboss.logmanager.Logger.getLogger("");
            logger.setLevel(java.util.logging.Level.ALL);
            

            然后从netty获取详细的日志记录,下面已经做到了

            org.slf4j.impl.SimpleLogger.setLevel(org.slf4j.impl.SimpleLogger.TRACE);
            

            【讨论】:

            • org.slf4j.impl.SimpleLogger 在当前 v1.7.30 中没有 setLevel()
            【解决方案7】:

            这是一个控制器

            @RestController
            @RequestMapping("/loggers")
            public class LoggerConfigController {
            
            private final static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(PetController.class);
            
            @GetMapping()
            public List<LoggerDto> getAllLoggers() throws CoreException {
                
                LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
                
                List<Logger> loggers = loggerContext.getLoggerList();
                
                List<LoggerDto> loggerDtos = new ArrayList<>();
                
                for (Logger logger : loggers) {
                    
                    if (Objects.isNull(logger.getLevel())) {
                        continue;
                    }
                    
                    LoggerDto dto = new LoggerDto(logger.getName(), logger.getLevel().levelStr);
                    loggerDtos.add(dto);
                }
                
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("All loggers retrieved. Total of {} loggers found", loggerDtos.size());
                }
                
                return loggerDtos;
            }
            
            @PutMapping
            public boolean updateLoggerLevel(
                    @RequestParam String name, 
                    @RequestParam String level
            )throws CoreException {
                
                LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
                
                Logger logger = loggerContext.getLogger(name);
                
                if (Objects.nonNull(logger) && StringUtils.isNotBlank(level)) {
                    
                    switch (level) {
                        case "INFO":
                            logger.setLevel(Level.INFO);
                            LOGGER.info("Logger [{}] updated to [{}]", name, level);
                            break;
                            
                        case "DEBUG":
                            logger.setLevel(Level.DEBUG);
                            LOGGER.info("Logger [{}] updated to [{}]", name, level);
                            break;
                            
                        case "ALL":
                            logger.setLevel(Level.ALL);
                            LOGGER.info("Logger [{}] updated to [{}]", name, level);
                            break;
                            
                        case "OFF":
                        default: 
                            logger.setLevel(Level.OFF);
                            LOGGER.info("Logger [{}] updated to [{}]", name, level);
                    }
                }
                
                return true;
            }
            

            }

            【讨论】:

              猜你喜欢
              • 2010-10-17
              • 2012-03-26
              • 1970-01-01
              • 2012-09-20
              • 2014-02-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-06-19
              相关资源
              最近更新 更多