2015-12-30 3 views
4

Мне нужно обработать дублирование конкретных исключений в моих журналах.Игнорировать запись дублированных сообщений об исключениях из сторонних библиотек

Я использую slf4j и logback для входа в мое приложение. Я использую некоторые внешние службы (DB, apache kafka, сторонние библиотеки и т. Д.). Когда соединение было разорвано до такой службы я получил исключение, такие как

[kafka-producer-network-thread | producer-1] WARN o.a.kafka.common.network.Selector - Error in I/O with localhost/127.0.0.1 
java.net.ConnectException: Connection refused: no further information 
    at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[na:1.8.0_45] 
    at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:717) ~[na:1.8.0_45] 
    at org.apache.kafka.common.network.Selector.poll(Selector.java:238) ~[kafka-clients-0.8.2.0.jar:na] 
    at org.apache.kafka.clients.NetworkClient.poll(NetworkClient.java:192) [kafka-clients-0.8.2.0.jar:na] 
    at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:191) [kafka-clients-0.8.2.0.jar:na] 
    at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:122) [kafka-clients-0.8.2.0.jar:na] 
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45] 

Проблема заключается в том, что я получил это сообщение каждый второй. Это сообщение об исключении наводнит мой файл журнала, поэтому в N-часах я буду иметь несколько ГБ в лог-файле.

Я хочу иметь сообщение журнала об этом исключении один раз в 1-5 минут. Есть ли способ игнорировать дублирование исключений в файле журнала?

Возможные решения:

  1. Игнорировать все журналы для конкретного пакета и класса. [плохо, beucase я могу пропустить важное сообщение]

  2. http://logback.qos.ch/manual/filters.html#DuplicateMessageFilter Используйте [плохо, потому что я могу установить только свойства AllowedRepetitions или CacheSize. Это будет соответствовать всем сообщениям, но мне нужно только конкретное исключение]

  3. Напишите пользовательский фильтр Возможно, вы уже знаете, какие решения уже есть?

ответ

0

Очень легко написать новый турбофильтр и реализовать любую логику, чтобы отклонить некоторые конкретные протоколирования.

Я ilemented нового фильтра следующей конфигурацией logback.xml

<turboFilter class="package.DuplicationTimeoutTurboFilter"> 
    <MinutesToBlock>3</MinutesToBlock> 
    <KeyPattern> 
     <loggerClass>org.apache.kafka.common.network.Selector</loggerClass> 
     <message>java.net.ConnectException: Connection refused: no further information</message> 
    </KeyPattern> 
</turboFilter> 

и реализация:

import ch.qos.logback.classic.Level; 
import ch.qos.logback.classic.Logger; 
import ch.qos.logback.classic.turbo.TurboFilter; 
import ch.qos.logback.core.spi.FilterReply; 
import org.slf4j.Marker; 

import java.time.LocalDateTime; 
import java.util.Arrays; 
import java.util.HashSet; 
import java.util.Objects; 
import java.util.Set; 
import java.util.concurrent.ConcurrentHashMap; 
import java.util.stream.Collectors; 

public class DuplicationTimeoutTurboFilter extends TurboFilter { 

    private static final int CLEAN_UP_THRESHOLD = 1000; 
    private ConcurrentHashMap<KeyPattern, LocalDateTime> recentlyMatchedPatterns = new ConcurrentHashMap<>(); 

    private Set<KeyPattern> ignoringPatterns = new HashSet<>(); 

    private long minutesToBlock = 3L; 

    @Override 
    public FilterReply decide(Marker marker, Logger logger, Level level, String format, Object[] params, Throwable t) { 
     String rawLogMessage = format + Arrays.toString(params) + Objects.toString(t); //sometimes throwable can be inserted into params argument 

     Set<KeyPattern> matchedIgnoringSet = ignoringPatterns.stream() 
       .filter(key -> match(key, logger, rawLogMessage)) 
       .collect(Collectors.toSet()); 

     if (!matchedIgnoringSet.isEmpty() && isLoggedRecently(matchedIgnoringSet)) { 
      return FilterReply.DENY; 
     } 

     return FilterReply.NEUTRAL; 
    } 

    private boolean match(KeyPattern keyPattern, Logger logger, String rawText) { 
     String loggerClass = keyPattern.getLoggerClass(); 
     String messagePattern = keyPattern.getMessage(); 
     return loggerClass.equals(logger.getName()) && rawText.contains(messagePattern); 
    } 

    private boolean isLoggedRecently(Set<KeyPattern> matchedIgnoredList) { 
     for (KeyPattern pattern : matchedIgnoredList) { 
      LocalDateTime now = LocalDateTime.now(); 

      LocalDateTime lastLogTime = recentlyMatchedPatterns.putIfAbsent(pattern, now); 
      if (lastLogTime == null) { 
       return false; 
      } 

      LocalDateTime blockedTillTime = lastLogTime.plusMinutes(minutesToBlock); 
      if (blockedTillTime.isAfter(now)) { 
       return true; 
      } else if (blockedTillTime.isBefore(now)) { 
       recentlyMatchedPatterns.put(pattern, now); 
       cleanupIfNeeded(); 
       return false; 
      } 
     } 
     return true; 
    } 

    private void cleanupIfNeeded() { 
     if (recentlyMatchedPatterns.size() > CLEAN_UP_THRESHOLD) { 
      LocalDateTime oldTime = LocalDateTime.now().minusMinutes(minutesToBlock * 2); 
      recentlyMatchedPatterns.values().removeIf(lastLogTime -> lastLogTime.isAfter(oldTime)); 
     } 
    } 

    public long getMinutesToBlock() { 
     return minutesToBlock; 
    } 

    public void setMinutesToBlock(long minutesToBlock) { 
     this.minutesToBlock = minutesToBlock; 
    } 

    public void addKeyPattern(KeyPattern keyPattern) { 
     ignoringPatterns.add(keyPattern); 
    } 

    public static class KeyPattern { 
     private String loggerClass; 
     private String message; 

     //constructor, getters, setters, equals, hashcode 
    } 
} 
0

Я думаю, что ваш лучший вариант - просто расширение DuplicateMessageFilter, которое вы уже нашли. Это не является окончательным, и это довольно легко:

  1. реализовать новый TurboFilter с методом фильтра на основе имени класса или ExceptionType или что-нибудь еще вы хотите, чтобы ваше первоначальное решение, основанное на

  2. затем делегировать на родительский класс для двуличности проверки

параметры, которые вы имеете в наличии:

public FilterReply decide(Marker marker, Logger logger, Level level, 
    String format, Object[] params, Throwable t) { 

Включите оба Throwable и Logger.

+0

спасибо, это очень легко писать новые TurboFilter – Geniy

Смежные вопросы