Java 包装log4j还是创建自定义记录器?

Java 包装log4j还是创建自定义记录器?,java,logging,log4j,audit-logging,Java,Logging,Log4j,Audit Logging,我有一个应用程序需要记录两种不同类型的消息:应用程序日志消息和审核消息。应用程序日志消息与标准lo4jLogger完美匹配,但审核日志需要几个参数 我认为我需要包装log4j,以便向debug()、info()等方法添加额外的必需参数,但我讨厌包装log4j的想法。我应该: 完全包装log4j,并提供我自己的Logger类来调用场景后面的log4j记录器 扩展log4jLogger类并添加带有我所需参数的“审计日志”方法 做一些更优雅的事情,这样我就不用包装日志库了 log4j记录器的错误、警告

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

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

  • 完全包装log4j,并提供我自己的
    Logger
    类来调用场景后面的log4j记录器
  • 扩展log4j
    Logger
    类并添加带有我所需参数的“审计日志”方法
  • 做一些更优雅的事情,这样我就不用包装日志库了

  • log4j
    记录器的
    错误
    警告
    等方法的“消息”是任意对象;它不需要是字符串。您可以创建自己的“message”类来包含不同的参数。日志记录器可以通过为审计记录器的附加器使用自定义的
    布局
    类以不同的方式附加数据。

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

    private final static Logger log = new Logger(MyClass.class);
    
    并为您的审核日志创建一个特定类别:

    private final static Logger log = new Logger("AuditTrail");
    
    使用不同的appender,您可以跨多个类共享acc,这将允许您在配置文件中随时配置输出目标和格式


    希望这有帮助。

    可能您可以阅读log4j的api NDC/MDC。希望能对您有所帮助。

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

    (归功于中的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);
        }
    }
    
    现在,根据Logger对象,在主类的布局中使用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());
    

    我希望这有帮助

    这是一个好主意,但我没有看到一种方法来强制开发人员为审核日志项提供所需的参数。不,除了在运行时失败(这可能不是您想要的)之外,没有(简单的)方法来强制执行日志消息的对象的性质。但不管怎么说,日志记录的大部分内容都是关于最佳实践的,因此我认为这里与一般意义上的日志记录没有太大区别。是的,如果我们的日志记录只是一种“最佳实践”,并且在某些情况下不是客户要求的,那就好了。我想我必须包装log4j才能添加所需的参数。太糟糕了,但应该不会太难。仍按上述建议使用自定义
    布局。使用自定义日志记录方法创建
    Logger
    的扩展,将消息和附加参数包装为单独的对象。自定义日志记录方法的实现可以简单地调用标准方法的超类版本(
    error
    ,等等)。标准方法的版本可以用注释标记,如
    Deprecated
    ,这将在编译时产生警告(甚至错误)。这将强制使用自定义日志记录方法。
    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());