如何以编程方式更改根日志记录级别

Kai*_*nad 134 java logging logback

我有以下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>
Run Code Online (Sandbox Code Playgroud)

现在,在发生特定事件时,我想以编程方式将根记录器的级别从调试更改为错误.我不能使用变量替换,我必须在代码中执行此操作.

怎么做到呢 ?谢谢.

dog*_*ane 221

试试这个:

import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;

Logger root = (Logger)LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
root.setLevel(Level.INFO);
Run Code Online (Sandbox Code Playgroud)

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

<configuration scan="true" scanPeriod="30 seconds" > 
  ...
</configuration> 
Run Code Online (Sandbox Code Playgroud)

  • 应该注意的是,slf4j的目的是抽象掉日志框架,但是第一种方法通过直接引用日志框架来消除它. (62认同)
  • Slf4j提供了一个API,以便库可以使用应用程序开发人员想要的任何日志框架来记录应用程序日志.关键是应用程序开发人员仍然必须选择日志框架,依赖它并进行配置.像dogbane一样配置记录器并没有违反这个原则. (4认同)
  • @JohnWiseman如果你想配置它,那么你必须在某处*配置它.由于slf4j在这方面没有提供任何东西,因此总会有依赖于底层记录器的东西.无论是代码还是配置文件.+++如果它应该按OP请求以编程方式完成,那么你别无选择.仍然存在优势:1.只有很小一部分代码依赖于具体的记录器引擎(并且可以编写它以便它可以处理不同的实现).2.您也可以配置使用其他记录器编写的库. (4认同)
  • 如果这样做并获得ClassCastException,则很可能是由于在类路径上有多个SLF4J绑定.日志输出将指示此信息以及存在哪些绑定,以便您确定需要排除哪个(哪些). (3认同)
  • 它确实违反了原则.否则,为什么要使用slf4j呢?为什么不调用`logback`方法来进行日志记录? (2认同)
  • @JohnWiseman Logback是从头开始设计的,是SLF4J的实现;与说log4j不同,没有“ logback API”与SLF4J完全分开。调用“ logback方法”的唯一原因将是诸如此类,SLF4J API并未涵盖。 (2认同)
  • 为什么对于诸如Logging之类的东西必须如此复杂,为什么不应该有直接的方法来更改代码本身中的Logging级别。遵循特定库的原理如何优先于其简单性?来自Python世界,我无法理解为什么Java / Scala中像Logging这样简单的事情如此复杂。 (2认同)

Rag*_*ram 10

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

logback手册,我看到了

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

也许这可以帮助你改变价值?

  • 然后呢?rootLogger 将是 org.slf4j.Logger 的实例,它没有 setLevel 方法。 (2认同)

Tod*_*lev 10

使用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]
Run Code Online (Sandbox Code Playgroud)


Sim*_*ion 5

正如其他人所指出的那样,您只需创建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"));
}
}
Run Code Online (Sandbox Code Playgroud)


SAT*_*uke 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>
Run Code Online (Sandbox Code Playgroud)
MDC.put("LOG_LEVEL", "INFO");
Run Code Online (Sandbox Code Playgroud)