Як змінити рівень кореневого журналу програмно для входу


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>

Тепер, після виникнення конкретної події, я хочу програмно змінити рівень кореневого реєстратора від налагодження до помилки . Я не можу використовувати змінну підстановку, обов'язково потрібно робити це в коді.

Як це можна зробити? Дякую.

Відповіді:


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

Зауважте, що ви можете також повідомити, що потрібно періодично сканувати конфігураційний файл так:

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

64
Слід зазначити, що метою slf4j є абстрагування рамки ведення журналу, але цей перший метод усуває це шляхом прямого посилання на структуру журналу.
Тім Готьє

3
Якщо ви зробите це і отримаєте ClassCastException, це, швидше за все, пов'язано з наявністю декількох прив'язок SLF4J на classpath. Вихід з журналу вказуватиме це та які прив'язки є для того, щоб ви могли визначити, яку (і) потрібно виключити.
icfantv

4
Slf4j надає API, щоб бібліотеки могли реєструвати журнали програм, використовуючи те, що бажає розробник програми. Справа в тому, що розробник додатків все-таки повинен вибрати рамку журналу, залежати від нього та налаштувати його. Настроювання лісоруба так, як це робиться собака, не порушує цього принципу.
Макс

4
@JohnWiseman Якщо ви хочете, щоб він був налаштований, вам доведеться його десь налаштувати . Оскільки slf4j нічого не пропонує в цьому відношенні, завжди буде залежати щось від основного реєстратора. Будь це фрагмент коду або файл конфігурації. +++ Якщо це потрібно робити програмно, як вимагає ОП, то у вас немає вибору. Проте переваги залишаються: 1. Тільки крихітна частина коду залежить від конкретного двигуна реєстратора (і він може бути записаний так, що він може працювати з різними реалізаціями). 2. Ви також можете налаштувати бібліотеки, написані за допомогою інших реєстраторів.
maaartinus

4
Чому це повинно бути настільки складним для чогось на кшталт Logging, чи не повинен бути прямий спосіб змінити рівень журналу в самому коді. Як дотримання принципу певної бібліотеки має перевагу над її простотою? Походячи із світу Python, я не розумію, чому щось так просто, як ведення журналу, настільки складне в Java / Scala.
Абхіндандан Дюбі

11

Я припускаю, що ви використовуєте зворотний зв'язок (з файлу конфігурації).

З посібника з зворотного зв'язку , я бачу

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

Можливо, це може допомогти вам змінити значення?


10

за допомогою зворотного зв'язку 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 для програмного зміни рівня журналу. Нижче наведений приклад - приклад зміни рівня журналу на поточному потоці. Такий підхід не створює залежності від реалізації зворотного зв'язку (API SLF4J містить 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);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.