【问题标题】:Wrap log4j or create custom logger?包装 log4j 或创建自定义记录器?
【发布时间】:2011-05-16 22:01:22
【问题描述】:

我有一个应用程序需要记录两种不同类型的消息:应用程序日志消息和审核消息。应用程序日志消息与标准 lo4j Logger 完美匹配,但审计日志有几个必需参数。

我认为我需要包装 log4j 以将额外的必需参数添加到 debug()info() 等方法,但我讨厌包装 log4j 的想法。我应该:

  1. 完全包装 log4j 并提供我自己的 Logger 类,它在后台调用 log4j 记录器?
  2. 扩展 log4j Logger 类并使用我所需的参数添加“审计日志”方法?
  3. 做一些更优雅的事情,这样我就不用包装日志库了...

【问题讨论】:

    标签: java logging log4j audit-logging


    【解决方案1】:

    log4j Loggererrorwarn 等方法的“消息”是任意对象;它不需要是一个字符串。您可以创建自己的“消息”类来包含不同的参数。记录器可以通过为审计记录器的附加器使用自定义Layout 类来以不同的方式附加数据。

    【讨论】:

    • 这是个好主意,但我没有看到强制开发人员为审计日志条目提供所需参数的方法。
    • 不,除了在运行时失败(这可能不是您想要的)之外,没有(简单的)方法可以强制执行日志消息对象的性质。但无论如何,大部分日志记录都是关于最佳实践的,所以我认为这里与一般意义上的日志记录没有太大区别。
    • 是的,如果我们的日志记录只是一种“最佳实践”,并且在某些情况下我们的客户的要求不需要这样做。我想我坚持包装 log4j 以添加所需的参数。
    • 太糟糕了,但应该不会太难。仍然使用上面推荐的自定义Layout。使用自定义日志记录方法创建 Logger 的扩展,将消息和附加参数包装为单独的对象。自定义日志记录方法的实现可以简单地调用标准方法的超类版本(error等)您的版本的标准方法可以用注释标记,如Deprecated,这将在编译时产生警告(甚至是错误)。这应该强制使用自定义日志记录方法。
    【解决方案2】:

    我认为您可以将 log4j 用于您的应用程序日志,创建如下日志:

    private final static Logger log = new Logger(MyClass.class);
    

    并为您的审核日志创建一个特定的类别:

    private final static Logger log = new Logger("AuditTrail");
    

    拥有一个可以跨多个类共享的不同附加程序将允许您在配置文件中根据需要配置输出目标和格式。

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      这将起作用: 到目前为止,这是我得到的最好的解决方案......

      (感谢LOG4J: Modify logged message using custom appender中的hellojava

      创建一个自定义的 Log4j 布局,例如:

      import java.util.HashMap;
      import java.util.Map;
      
      import org.apache.log4j.Level;
      import org.apache.log4j.PatternLayout;
      import org.apache.log4j.spi.LoggingEvent;
      
      public class AuditLayout extends PatternLayout {
          // Audit Summary Map:
          // <Level, Counter>
      
          private static Map<Level, Integer> auditMap = new HashMap<Level, Integer>();
      
          public static Map<Level, Integer> getAuditMap() {
              return auditMap;
          }
      
          public static void setAuditMap(Map<Level, Integer> auditMap) {
              AuditLayout.auditMap = auditMap;
          }
      
          @Override
          public String format(LoggingEvent event) {
      
              if (event.getMessage() != null && event.getMessage() instanceof String) {
                  // Check the message level and update the audit object accordingly:
                  if (!auditMap.containsKey(event.getLevel())) {
                      auditMap.put(event.getLevel(), 1); 
                  } else {
                      int i = auditMap.get(event.getLevel());    
                      i++;
                      auditMap.put(event.getLevel(), i); 
                  }
              }
              return super.format(event);
          }
      }
      

      这是一个非常简单的布局,它检查日志级别并在 Map 中保存摘要; 即调试> 2,信息> 10 等等。

      在您的 log4j.properties 文件中设置新布局(使用您的附加程序之一):

      # CONSOLE:
      log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
      log4j.appender.CONSOLE.Threshold=DEBUG
      # BEFORE::: log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
      # AFTER:::
      log4j.appender.CONSOLE.layout=com.ca.utils.AuditLayout
      log4j.appender.CONSOLE.layout.ConversionPattern=%d{MM/dd/yyyy HH:mm:ss} %-5p %c line: %L - %m%n
      

      现在,基于 Logger 对象,在 Main 类的 Layout 中使用您的 auditMap:

      private static AuditLayout auditLayout = null;
      ...
      if (log.getRootLogger().getAppender("CONSOLE").getLayout() instanceof AuditLayout)
          auditLayout = (AuditLayout) log.getRootLogger().getAppender("CONSOLE").getLayout();
      ...
      System.out.println("auditLayout: " + auditLayout.getAuditMap().toString());
      

      我希望这会有所帮助!

      【讨论】:

        【解决方案4】:

        也许你可以阅读 log4j 的 api NDC/MDC。希望对你有帮助。

        【讨论】:

          猜你喜欢
          • 2017-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-18
          • 1970-01-01
          相关资源
          最近更新 更多