【问题标题】:Using same log4j logger in standalone java application在独立的 Java 应用程序中使用相同的 log4j 记录器
【发布时间】:2010-06-14 14:32:06
【问题描述】:

我有一些代码是一个独立的 Java 应用程序,包含 30 多个类。

其中大部分继承自其他一些基类。

每个类都有这个方法来获取和使用 log4j 记录器

public static Logger getLogger() {
    if (logger != null) return logger;
    try {
        PropertyUtil propUtil = PropertyUtil.getInstance("app-log.properties");
        if (propUtil != null && propUtil.getProperties() != null)
            PropertyConfigurator.configure(propUtil.getProperties ());
        logger = Logger.getLogger(ExtractData.class);
        return logger;
    } catch (Exception exception) {
        exception.printStackTrace();
    }
}

A) 我的问题是,是否应该将其重构为一些常见的记录器,该记录器被初始化一次并被所有类使用?这是更好的做法吗?

B) 如果是,怎么做?如何传递记录器?

C) 这实际上在代码中使用的不是Logger.debug(),而是getLogger().debug()。 这对性能有什么影响?

【问题讨论】:

  • 我可能错了,但我不认为 PropertyConfigurer.configure() 是线程安全的 - 所以如果你的代码是多线程的,从多个线程调用这个 getLogger() 方法可能会导致问题。最好使用 Péter Török 概述的标准 log4j 用法
  • @matt b - 感谢您的指出。我会检查使用情况,因为这段代码可能是从多个线程执行的

标签: java log4j


【解决方案1】:

A) 在 Log4J 中,您有记录器层次结构,而不是单个记录器。这通常归结为每个类一个记录器,其中记录器由类名标识。记录器是这样初始化的:

private static final Logger logger = Logger.getLogger(MyClass.class);

这是一个很好的做法,因为它允许您微调应用程序中模块(包)甚至单个类的日志记录行为。因此,您可以禁用某些包的日志记录,在其他包中以 INFO 级别登录,并为某些关键类(例如)登录 DEBUG 级别。当你想捕捉错误时。

B) 但是,如果您想要一个单一的记录器,只需在每个类中使用根记录器:

private static final Logger logger = Logger.getLogger();

C) 对于不太复杂的方法的调用,性能差异可能可以忽略不计,因为 JIT 编译器无论如何都会积极内联调用。对于复杂的方法,这更像是一个悬而未决的问题。

请注意,您显示的方法通过加载记录器配置来完成不必要的工作 - 如果您将配置文件命名为 log4j.properties 并将其放在类路径中,这将由 Log4J 自动完成。但是,即使您需要使用非标准的配置文件名,您仍然可以在启动时将 Log4J 配置加载到一个位置,并省略记录器的延迟加载。那么剩下的就是

private static final Logger logger = Logger.getLogger(ExtractData.class);

private static Logger getLogger() {
    return logger;
}

这肯定会被编译器内联。尽管如此,您可能希望保留getLogger,以避免修改大量调用者代码。

请注意,getLogger 不必是public,因为无论如何所有类都应该有自己的记录器引用。

【讨论】:

    【解决方案2】:

    A) 取决于,但我认为每类记录器的粒度是使用 log4j 实用程序的一部分。如果您愿意,可以将日志信息从一个类重定向或将它们全部发送到同一个文件。

    B) 您不会传递记录器,您只需使用 Logger.getLogger() 方法来使用根记录器。

    C) 在性能方面可能并不大。如果它还不是静态的,则可以选择将您的 getLogger() 方法指示为 final 以建议它应该被内联。彼得的答案在这里更好,正如他所指出的,如果方法足够简单,无论如何它很可能会被内联。

    【讨论】:

    • re C: getLogger() 已经是静态的,因此将其设为 final 将是多余的。
    • 声明一个(非静态)方法final 无论如何都无关紧要 - JIT 编译器知道它是否在实际上下文中被覆盖,因此它可以内联相应地。
    【解决方案3】:

    每个类都可以得到它自己的记录器

    final static private Logger log = Logger.getLogger("com.company.package.MyClass");
    

    这使您可以按类调整 log4j 设置,这比标准记录器更灵活。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-23
      • 2019-06-14
      • 2014-01-22
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多