【问题标题】:Ignore logging of duplicated exception messages of third party libs忽略第三方库的重复异常消息的日志记录
【发布时间】:2016-04-04 13:07:11
【问题描述】:

我需要在我的日志中处理重复的特定异常。

我使用 slf4j 和 logback 来登录我的应用程序。我使用一些外部服务(数据库、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 小时内有几 GB 的日志文件。

我希望每 1-5 分钟记录一次有关此异常的日志消息。有什么方法可以忽略日志文件中重复的异常?

可能的解决方案:

  1. 忽略特定包和类的所有日志。 [不好,因为我可以跳过重要消息]

  2. 使用http://logback.qos.ch/manual/filters.html#DuplicateMessageFilter [不好,因为我只能设置属性 AllowedRepetitions 或 CacheSize。它会匹配所有消息,但我只需要特定的例外]

  3. 编写自定义过滤器 也许,您知道已经实施的解决方案?

【问题讨论】:

    标签: java logging apache-kafka slf4j logback


    【解决方案1】:

    我认为您最好的选择只是扩展您已经找到的DuplicateMessageFilter。它不是最终的,很容易:

    1. 使用基于类名或 exceptionType 的过滤器方法或您希望做出初始决定的任何其他内容实现新的 TurboFilter

    2. 然后委托给父类进行重复性检查

    你可用的参数:

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

    包括ThrowableLogger

    【讨论】:

      【解决方案2】:

      编写新的涡轮过滤器并实现任何逻辑来拒绝某些特定的日志记录真的很容易。

      我已经在下一个配置中添加了新过滤器 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
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-06-10
        • 1970-01-01
        • 1970-01-01
        • 2016-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-10
        相关资源
        最近更新 更多