web-dev-qa-db-ja.com

特定のクラスにいる間、他のライブラリのログバックログをオフにします

Springの@Scheduledアノテーションを使用して、数秒ごとにメソッドを正常に実行しています。唯一の問題は、この方法のために、HibernateとSpringからトランザクションなどに関するログメッセージをたくさん受け取ることです。

アプリケーション内の他のトランザクションでこの情報を受け取りたいので、ログレベルを同じに保ちたいと思います。

特定のメソッドの実行中に別のライブラリのロギングを一時的に抑制する方法はログバックにありますか?

17
johnktims

はい、これはスレッドごとに実行できます。

Filters および MDC(Mapped Diagnostic Context) を使用する必要があります。このソリューションは、onlyが、@Scheduledメソッドを実行しているスレッドで発生するロギングに影響を与えます。

手順の概要

  1. @Scheduledメソッドで、そのスレッドのMDCにエントリを追加します。
  2. ch.qos.logback.core.filter.Filter<ILoggingEvent>の実装を作成します。これは、そのエントリがMDCに設定されている場合、FilterReply.DENYを返します。
  3. <appender>logback.xmlエントリにそのフィルタへの参照を追加します

ステップ1

@Scheduledメソッドを次のようにします。

@Scheduled(fixedRate=30000)
public void scheduledMethod () {
    try{
        MDC.put("scheduled", "true");

        // Your code here
    }finally{
        MDC.remove("scheduled");
    }
}

Springはスレッドを再利用する可能性があり、MDCはそれ以外の場合は値を保持するため、キーを削除することが重要であることを述べておく必要があります。

ステップ2

フィルタは次のようになります。

package my.domain.application.logging;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;

public class MDCFilter extends Filter<ILoggingEvent> {

  @Override
  public FilterReply decide(ILoggingEvent event) {    
    String scheduled = event.getMDCPropertyMap().get("scheduled");
    if ("true".equals(scheduled)) {
      return FilterReply.DENY;
    } else {
      return FilterReply.NEUTRAL;
    }
  }
}

ステップ3

logback.xmlに以下を追加します

<appender name="myAppender" class="ch.qos.logback.core.ConsoleAppender">
    <filter class="my.domain.application.logging.MDCFilter" />
    <!-- the rest of your appender -->
</appender>
18
durron597

はい:ロガーのログレベルを動的に設定できるため、時間の経過とともに変更できます。

理想的には、関連するクラス階層の最上位にロガーを配置し、ログレベルを必要に応じて設定するだけです。たとえば、休止状態の場合:

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

// When you want to temporarily change the log level
Logger orgHibernateLogger = LoggerFactory.getLogger("org.hibernate");
Level oldLogLevel = orgHibernateLogger.getLevel();
orgHibernateLogger.setLevel(Level.ERROR); // or whatever level you want

// When you want to return to the old log level
orgHibernateLogger.setLevel(oldLogLevel);

これは、関連する階層内の他のロガーがログレベルを明示的に構成していない限り機能するはずです。階層内の他のロガーが明示的にログレベルを構成している場合は、明示的に設定されたすべてのログレベルを一時的に調整し、最後にすべてを「通常」に戻す必要があります。

これは時間ベースのアプローチであり、コンテキストベースのアプローチではないことに注意してください。一時ログレベルの使用中に他のコードがライブラリを同時に使用すると、その一時ログレベルも取得されます。ログレベルは、通常に戻ったときにのみ「通常」に戻ります。一時ログレベルを使用しているときに他のコードの実行を妨げずに、それを回避する簡単な方法はないと思います。

編集:目的のスレッドでのみ不要なロギングをオフにできる方法については、Durron597による回答を参照してください。少し単純ではありませんが、機能するはずです。

5
Warren Dew

通常、ロギングフレームワークはpackageレベルのログ構成をサポートします。 logback.xmlファイルで次のようなことを行うことができます。

<configuration>
    <logger name="org.hibernate.transaction" level="OFF"/>   // change log level to suppress here
     <logger name="org.springframework.transaction" level="OFF"/>

    <root level="ALL">
        <appender class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{ISO8601} | %-5level | %thread | %logger{1} | %m%n</pattern>
            </encoder>
        </appender>
    </root>
</configuration>

jbossアプリケーションサーバーでは、以前に同じ問題が発生し、フィルタリングされた不要なログ以下のようなパッケージレベルのログ設定で:

<logger category="com.lftechnology.sbworkbench">
    <level name="DEBUG"/>
</logger>
<logger category="org.quartz">
    <level name="WARN"/>
</logger>
<logger category="com.liferay.portal">
    <level name="INFO"/>
</logger>
<logger category="org.jboss.as.server.deployment">
    <level name="ERROR"/>
</logger> 

特定の方法でライブラリのログインを抑制することに関心があるので、プログラムでそれを行い、終了時に復元する必要があります。しかし、それが特定のコードブロックに影響を与えるかどうかはわかりません。

さらに、アプリケーションがconcurrentlyを実行している場合は、以下のようにThreadLocalを使用できます。

public Class A implements Runnable {
    //you can later dynamically configure this variable also
    private static final ThreadLocal<Logger> CLASS_LOGGER = new ThreadLocal<Logger>(){
       Logger LOGGER = LoggerFactory.getLogger(A.class);
         return LOGGER;
       }

     @Override
 public void run() {
   //before calling your function change log level
   //as we declare local variable here this most likely  to affect log here only
   Logger Logger = LoggerFactory.getLogger("org.hibernate.transaction");
   Level oldLogLevel = Logger.getLevel(); 
   Logger.setLevel(Level.OFF); // 

   callYourFunction();

   //restore log level to previous
   Logger.setLevel(oldLogLevel);

 }

私も同様の答えがあります ここ

5
gyanu