ログバックのためにプログラムでルートロギングレベルを変更する方法


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 2013

4
Slf4jはAPIを提供するため、ライブラリはアプリケーション開発者が望むログフレームワークを使用してアプリケーションログを記録できます。ポイントは、アプリケーション開発者がログフレームワークを選択し、それに依存し、構成する必要があるということです。ロガーをdogbaneが行ったように構成しても、この原則に違反しません。
最大

4
@JohnWiseman構成する場合は、どこかで構成する必要があります。slf4jはこの点で何も提供しないため、基礎となるロガーに常に依存するものがあります。コードであれ、構成ファイルであれ、+++ OPが要求したとおりにプログラムで実行する必要がある場合は、選択肢がありません。それでも利点は残っています。1.コードのごく一部のみが具象ロガーエンジンに依存しています(さまざまな実装を処理できるように記述できます)。2.他のロガーを使用して作成されたライブラリーも構成できます。
maaartinus

4
Loggingのように複雑になる必要があるのはなぜですか?コード自体でログレベルを変更する直接的な方法があるべきではありません。特定のライブラリの原則に従うことは、その単純さよりもどのように優先されますか?Pythonの世界から来て、なぜLoggingのような単純なものがJava / Scalaで非常に複雑なのか理解できません。
Abhinandan Dubey

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を使用して、ログレベルをプログラムで変更できると思います。以下のコードは、現在のスレッドでロギングレベルを変更する例です。このアプローチでは、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");

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.