Java 日志记录 : log everything >debug but only when an error occured

标签 java logging

在请求处理期间,记录了一堆调试日志。如果出现问题,有时可能会记录错误。想法:当整个请求处理过程中没有错误发生时,我想忽略所有调试,但如果发生错误,我想在日志中看到所有之前和之后的调试。

是否有任何开箱即用的解决方案(在 log4j、logback 或任何其他程序中),或者我必须为我的 Logger 实现某种包装器,它将“缓存”每个线程的调试,直到需要它们为止?

最佳答案

它不是一个内置的解决方案,但它是我的草稿实现,它可以是非常小的并且易于集成。它使用 log4j2,如果您已经在使用 log4j2 或 slf4j,则无需更改客户端代码。

于是对应的测试用例

  @Test
  public void no_error_so_no_log() throws Exception {
    LogEventCollector.clean();
    try {
      log.debug("hello world");
      log.debug("some debug again");
    } finally {
      LogEventCollector.clean();
    }
  }

  @Test
  public void error_so_log_from_the_beginning() throws Exception {
    LogEventCollector.clean();
    try {
      log.debug("hello world");
      log.error("some error", new RuntimeException("whatever"));
      log.debug("some debug again");
    } finally {
      LogEventCollector.clean();
    }
  }

LogEventCollector 将负责对您的 Web 应用程序请求线程进行初始化和清理。它可以放入 servlet Filter 中。

我已经创建了我的自定义 Appender。 appender 的核心如下:

    @Override
    public void append(LogEvent event) {
      if (Level.ERROR.isLessSpecificThan(event.getLevel()))
        LogEventCollector.markError();
      if (!LogEventCollector.hadError()) {
        LogEventCollector.collect(event);
        return;
      }
      for (LogEvent collected : LogEventCollector.events())
        push_log_out(collected);
      //and the current one
      push_log_out(event);
    }

方法push_log_event 才是真正的日志记录。它可以是您的自定义实现或委托(delegate)给另一个实现(如 AsyncAppender)。

LogEventCollector 本身:

  public class LogEventCollector {
    static ThreadLocal<Context> LOG_COLLECTOR = new ThreadLocal<Context>() {
      @Override
      protected Context initialValue() {
        return new Context();
      }
    };

    public static void clean() {
      LOG_COLLECTOR.get().clean();
    }

    static class Context {
      boolean had_error = false;
      List<LogEvent> events = new ArrayList<LogEvent>();

      public void clean() {
        had_error = false;
        events = new ArrayList<LogEvent>();
      }
    }

    public static void markError() {
      LOG_COLLECTOR.get().had_error = true;
    }

    public static boolean hadError() {
      return LOG_COLLECTOR.get().had_error;
    }

    public static void collect(LogEvent event) {
      LOG_COLLECTOR.get().events.add(event);
    }

    public static List<LogEvent> events() {
      List<LogEvent> ret = LOG_COLLECTOR.get().events;
      LOG_COLLECTOR.get().events = new ArrayList<LogEvent>();
      return ret;
    }

  }

我觉得根据自己的需求定制一定够了。

关于Java 日志记录 : log everything >debug but only when an error occured,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31454904/

相关文章:

java - WHILE 在 ELSE 计算之前重复

grails - 为什么我不能让我的记录器写入 Grails 中的文件附加程序?

java - 在多个组件中记录全局 ID

php - 从php存储Logstash日志的最简单方法是什么

python - 'thread._local' 对象没有属性

java - 在 Java 中将本地时间戳转换为 UTC 时间戳

java - 如何在 Android Studio 项目中包含 .jar 库

java - 如何更改 Android 应用程序中的通知设置?

java - 使用Java获取MQ队列的ClusterName

python - 我要测试一个什么都不做的类吗?