로그 백을 위해 프로그래밍 방식으로 루트 로깅 수준을 변경하는 방법


144

다음 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로 변경하고 싶습니다 . 변수 대체를 사용할 수 없으므로 코드 내 에서이 작업을 수행해야합니다.

어떻게 할 수 있습니까? 감사.

답변:


235

이 시도:

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);

다음과 같이 구성 파일을 주기적으로 스캔하도록 logback에 지시 할 수 있습니다.

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

64
slf4j의 목적은 로깅 프레임 워크를 추상화하는 것이지만, 첫 번째 방법은 로깅 프레임 워크를 직접 참조하여이를 제거합니다.
Tim Gautier

3
이 작업을 수행하고 ClassCastException이 발생하면 클래스 경로에 여러 SLF4J 바인딩이 있기 때문일 수 있습니다. 로그 출력에이를 표시하고 제외해야 할 바인딩을 판별 할 수있는 바인딩이 표시됩니다.
icfantv

4
Slf4j는 API가 애플리케이션 라이브러리가 원하는 로그 프레임 워크를 사용하여 라이브러리가 애플리케이션 로그를 로깅 할 수 있도록 API를 제공합니다. 요점은 응용 프로그램 개발자가 여전히 로그 프레임 워크를 선택하고 의존하고 구성해야한다는 것입니다. Dogbane이 수행 한대로 로거를 구성해도이 원칙을 위반하지 않습니다.
Max

4
@JohnWiseman 구성하려면 원하는 위치 에 구성해야합니다 . slf4j는 이와 관련하여 아무것도 제공하지 않으므로 항상 기본 로거에 의존하는 것이 있습니다. 코드 또는 구성 파일이어야합니다. +++ OP가 요청한대로 프로그래밍 방식으로 수행해야하는 경우 선택할 수 없습니다. 여전히 장점은 다음과 같습니다. 1. 코드의 작은 부분 만 콘크리트 로거 엔진에 의존합니다 (다른 구현을 처리 할 수 ​​있도록 작성할 수 있음). 2. 다른 로거를 사용하여 작성된 라이브러리도 구성 할 수 있습니다.
maaartinus

4
로깅과 같은 이유로 왜 그렇게 복잡해야합니까? 코드 자체에서 로깅 수준을 변경하는 직접적인 방법이 없어야합니다. 특정 라이브러리의 원칙을 따르는 것이 단순성보다 어떻게 우선합니까? 파이썬 세계에서 왔을 때 Java / Scala에서 로깅과 같은 단순한 것이 왜 그렇게 복잡한 지 이해하지 못했습니다.
Abhinandan Dubey 2016 년

11

구성 파일에서 로그 백을 사용한다고 가정합니다.

에서 logback 설명서 , 나는 참조

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

아마도 이것이 값을 변경하는 데 도움이 될 수 있습니까?


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]

4

MDC를 사용하여 프로그래밍 방식으로 로깅 수준을 변경할 수 있다고 생각합니다. 아래 코드는 현재 스레드에서 로깅 수준을 변경하는 예입니다. 이 접근법은 로그 백 구현에 대한 종속성을 작성하지 않습니다 (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");

3

다른 사람들이 지적했듯이, 단순히 내부에 등록 / 발생한 로깅 이벤트를 수신 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"));
}
}

0

나는 성공하는 것 같다

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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.