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