【问题标题】:May I create logger in Log4j2 per Level, not per class?我可以在 Log4j2 中为每个级别而不是每个班级创建记录器吗?
【发布时间】:2017-03-09 08:54:29
【问题描述】:

我正在接管一个旧的 java 项目。原来的设计师已经走了。 在这个项目中,它以静态方式使用 Log4j,如下所示:

public class LogUtil {
private static final String FQCN = LogUtil.class.getName();
private static final Logger logger1 = Logger.getLogger("INFO");
private static final Logger logger2 = Logger.getLogger("ERROR");

public static void info(Object message) {
    if (logger1.isInfoEnabled()) {
        forcedLog(logger1, Level.INFO, message);
    }
}


public static void error(Object message) {
    forcedLog(logger2, Level.ERROR, message);
}


private static void forcedLog(Logger logger, Level level, Object message) {
    logger.callAppenders(new LoggingEvent(FQCN, logger, level, message, null));
}

}

然后其他类可以很容易地用LogUtil.error("")LogUtil.info("")写日志。 并且 INFO 记录器和 ERROR 记录器被配置为写入单独的文件。

但是在Log4j2中,找不到LoggingEvent类。

那么问题来了,如果我要使用Log4j2,应该如何修改这个类呢? (也许使用 log4j2 包中提供的 Log4j 1.x 桥接器?)

以这种方式使用记录器合理吗?似乎比为每个类创建记录器更容易。是否有性能或其他方面的问题?

【问题讨论】:

    标签: java logging log4j log4j2


    【解决方案1】:

    那么问题来了,如果我要使用Log4j2,应该如何修改这个类呢? (也许使用 log4j2 包中提供的 Log4j 1.x 桥接器?)

    可以重写它以使用公共 API,而不是依赖底层实现细节。所以,像这样:

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    public class LogUtil {
        private static final Logger TRACE_LOGGER = LogManager.getLogger("TRACE");
        private static final Logger DEBUG_LOGGER = LogManager.getLogger("DEBUG");
        private static final Logger INFO_LOGGER = LogManager.getLogger("INFO");
        private static final Logger WARN_LOGGER = LogManager.getLogger("WARN");
        private static final Logger ERROR_LOGGER = LogManager.getLogger("ERROR");
        private static final Logger FATAL_LOGGER = LogManager.getLogger("FATAL");
    
        public static void trace(Object msg){
            TRACE_LOGGER.trace(msg);
        }
    
        public static void debug(Object msg){
            DEBUG_LOGGER.debug(msg);
        }
    
        public static void info(Object msg) {
            INFO_LOGGER.info(msg);
        }
    
        public static void warn(Object msg){
            WARN_LOGGER.warn(msg);
        }
    
        public static void error(Object msg) {
            ERROR_LOGGER.error(msg);
        }
    
        public static void fatal(Object msg){
            FATAL_LOGGER.fatal(msg);
        }
        ...
    }
    

    以这种方式使用记录器合理吗?似乎比为每个类创建记录器更容易。是否有性能或其他方面的问题?

    我不明白向一个类添加 3 行是多么容易。创建一个记录器(在 log4j2 中)只需要这样:

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    ...
    private static final Logger logger = LogManager.getLogger();
    

    至于潜在的问题,使用这个实现你放弃了 log4j 的很多功能。

    1. 您不能基于包或类更改日志级别,因为所有类共享相同的记录器。也许您想为正在处理的新类打开 TRACE 日志记录,但您不希望其他类的任何 TRACE 日志,因为它会使日志文件混乱 - 您将无法轻松进行此类更改。
    2. 您不能以包或类为基础更改附加程序,因为所有类再次共享相同的记录器。也许您希望将正在处理的新包中的所有日志发送到单独的文件中,以便您可以更轻松地查看新代码正在执行的操作,而无需手动过滤日志。也许您希望在开发过程中在单个文件中查看来自特定类或包的所有日志,以便您可以更轻松地跟踪执行,而无需跳转到不同的文件。

    【讨论】:

    • 非常感谢您的回答。正如您所说,每个类一个记录器,以更灵活地控制某些类打印的日志。
    • 我尝试了你的第一种方法,但是日志跟踪都像LogUtil.info(LogUtil.java:23) test 真实的地方调用 LogUtil.info 没有被打印到日志中。要记录日志的真实位置,似乎我必须直接调用 logger.info() 。我想通过logger = LogManager.getLogger(ClassA.class); 创建记录器,因此在每个具有类名的类中实现可能需要一些时间。我会尝试你的方式,并将所有 LogUtil.info() 替换为 logger.info()。谢谢。
    • 我明白你在记录器声明中使用类名的意思。 log4j2 提供了采用零参数的getLogger() 方法。见log4j2 API documentation - 见最后一节关于“记录器名称”
    • 关于文件名和行号问题是的,这将是我建议的第一种方法的问题。公平地说,您并没有说您正在打印文件名和行号(大多数关心性能的人不会,因为它确实会影响性能)。因此,这将是不以您以前的方式使用记录器的另一个原因,因为这会增加您的问题的复杂性。
    猜你喜欢
    • 2011-03-09
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多