Отключить ведение журнала регистрации для других библиотек, в то время как в определенном классе

Я успешно использую аннотацию Spring @Scheduled для выполнения метода каждые несколько секунд. Единственная проблема заключается в том, что из-за этого метода я получаю много сообщений журнала о транзакциях и т.д. Из Hibernate и Spring.

Я хочу, чтобы уровни ведения журнала были одинаковыми, потому что мне нравится получать эту информацию для других транзакций в приложении.

Есть ли способ в журнале, чтобы временно запретить ведение журнала другой библиотеки при выполнении определенного метода?

Ответы

Ответ 1

Да, это можно сделать по-потоковой основе.

Вам нужно использовать Filters и MDC (сопоставленный диагностический контекст). Это решение будет только влиять на ведение журнала, которое происходит в потоке, выполняющем метод @Scheduled.

Обзор шагов

  • В вашем методе @Scheduled добавьте запись в MDC этого потока.
  • Создайте реализацию ch.qos.logback.core.filter.Filter<ILoggingEvent>, которая вернет FilterReply.DENY, если эта запись задана в MDC
  • Добавьте ссылку на этот фильтр в своей записи <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>

Ответ 2

Обычно среда ведения журнала поддерживает конфигурацию журнала пакет. Вы можете сделать что-то вроде ниже в файле 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> 

Поскольку вы заинтересованы в подавлении библиотечного журнала определенным методом, вам придется делать это программно и восстанавливать при выходе. Но я не уверен, что это повлияет на конкретный блок кода.

Более того, если ваше приложение работает одновременно, вы можете использовать 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);

 }

У меня есть аналогичный ответ здесь

Ответ 3

Да: вы можете динамически устанавливать уровни журналов журналов и, таким образом, изменять их с течением времени.

В идеале все, что вам нужно сделать, это получить логгер в верхней части соответствующей иерархии классов и установить уровень журнала на все, что вы хотите. Например, спящий режим:

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 для метода, который позволяет отключить нежелательное ведение журнала только в нужном потоке. Это немного менее просто, но похоже, что он должен работать.