如何使用多个类的log4j?

我目前正在用java编写一个大项目,有很多类,有些类很小,只用很少的方法代表对象。 我的主类中有一个记录器,它工作正常。 我希望能够只使用一个记录器(带一个控制台appender)和所有类。 我试图将对记录器的引用传递给不同的类,但它看起来不正确。 此外,有时候我在没有运行main的情况下对类运行测试,因此没有为其他类初始化记录器。

实现这一目标的最佳方法是什么,我的意思是,如何从不同的类登录到一个日志,类之间没有硬依赖关系,并且能够独立地使用每个类的日志?

如果我理解正确,你现在所拥有的是:

public class Main { public static final Logger LOGGER = Logger.getLogger(Main.class); } public class AnotherClass { public void doSomething() { Main.LOGGER.debug("value=" + value); } } 

或者,将对记录器的引用传递给类的构造函数。

首先,您可以通过简单地使用传递给Logger.getLogger的相同值来使用一个全局记录器,例如:

 public class Main { private static final Logger LOGGER = Logger.getLogger("GLOBAL"); } public class AnotherClass { private final Logger LOGGER = Logger.getLogger("GLOBAL"); public void doSomething() { LOGGER.debug("value=" + value); } } 

这使用完全相同的记录器,Logger.getLogger在两个调用中返回相同的对象。 您不再在类之间具有依赖关系,这将起作用。

我从你的评论中收集到的另一件事是你正在手动配置(使用BasicConfigurator.configure 。大多数情况下这不是必需的,你应该通过简单地添加log4j.properties或log4j.xml来进行配置。你的类路径。在Eclipse中,这是通过将它添加到src /(或src / main / resources,如果你正在使用maven)来完成的。如果你正在使用junit,那么将它添加到test / source目录(或src / test) / maven资源)。这是配置log4j的一个更好的长期方法,因为你不必在类之间传递信息。

此外,使用记录器的推荐方法是将类传递给Logger.getLogger()。 通过这种方式,您可以根据类名过滤输出,这通常比只有一个全局记录器更有用:

 public class Main { private static final Logger LOGGER = Logger.getLogger(Main.class); public static final main(String[] args) { LOGGER.debug("started"); } } public class AnotherClass { private final Logger LOGGER = Logger.getLogger(this.getClass()); public void doSomething() { LOGGER.debug("value=" + value); } } 

然后在log4j.properties中,您可以将单个appender配置为一个文件。

 # Set root logger level to DEBUG and its only appender to A1. log4j.rootLogger=DEBUG, A1 # A1 is set to be a ConsoleAppender. log4j.appender.A1=org.apache.log4j.ConsoleAppender # A1 uses PatternLayout. log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

最后,没有必要将所有记录器声明为静态。 如果您正在进行大量 [*]对象创建,这只会产生明显的差异。 将记录器声明为非静态字段允许您使用Logger.getLogger(this.getClass()); 在这种情况下,将一个记录器添加到一个类就成了一行的剪切和粘贴。 请参阅我是否应该声明日志引用是否为静态? (遗憾的是,维基页面的链接已被破坏),但slf4j页面也包含了很好的解释。 所以使用非静态字段除非你有充分的理由不这样做。

当Cameron说你应该尝试使用slf4j时它是正确的,它有一个杀手级function,你可以使用多个日志框架。

[*]我的意思很多。

您的记录器实例通常应该是privatestaticfinal 。 通过这样做,每个类将拥有它自己的记录器实例(在加载类后创建),这样您就可以识别创建日志记录的类,并且您不再需要跨类传递记录器实例。

最好的方法是让每个类都有自己的记录器(以类命名),然后设置你的配置,使它们都附加到同一个appender。

例如:

 class A { private static final Logger log = Logger.getLogger(A.class); } class B { private static final Logger log = Logger.getLogger(B.class); } 

然后你的log4j.properties看起来像log4j文档中的例子:

 # Set root logger level to DEBUG and its only appender to A1. log4j.rootLogger=DEBUG, A1 # A1 is set to be a ConsoleAppender. log4j.appender.A1=org.apache.log4j.ConsoleAppender # A1 uses PatternLayout. log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n 

AB都将记录到根记录器,因此记录到同一个appender(在本例中为控制台)。

这将为您提供所需的内容:每个类都是独立的,但它们都写入相同的日志。 您还可以获得奖励function,您可以在log4j配置中更改每个类的日志记录级别。

顺便说一句,如果项目仍处于早期开发阶段,您可能需要考虑转移到slf4j。 slf4j对log4j有一些改进,使它更容易使用。

您有多个记录器实例的原因是因为您希望它们在记录时表现不同(通常通过打印出它们配置的类名)。 如果您不关心这一点,您可以在类中创建一个静态记录器实例,并在整个地方使用它。

要创建单个记录器,您只需创建一个静态实用程序日志记录类作为单点记录器,因此如果我们需要更改记录器包,您将只更新此类。

 final public class Logger { private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger("Log"); enum Level {Error, Warn, Fatal, Info, Debug} private Logger() {/* do nothing */}; public static void logError(Class clazz, String msg) { log(Level.Error, clazz, msg, null); } public static void logWarn(Class clazz, String msg) { log(Level.Warn, clazz, msg, null); } public static void logFatal(Class clazz, String msg) { log(Level.Fatal, clazz, msg, null); } public static void logInfo(Class clazz, String msg) { log(Level.Info, clazz, msg, null); } public static void logDebug(Class clazz, String msg) { log(Level.Debug, clazz, msg, null); } public static void logError(Class clazz, String msg, Throwable throwable) { log(Level.Error, clazz, msg, throwable); } public static void logWarn(Class clazz, String msg, Throwable throwable) { log(Level.Warn, clazz, msg, throwable); } public static void logFatal(Class clazz, String msg, Throwable throwable) { log(Level.Fatal, clazz, msg, throwable); } public static void logInfo(Class clazz, String msg, Throwable throwable) { log(Level.Info, clazz, msg, throwable); } public static void logDebug(Class clazz, String msg, Throwable throwable) { log(Level.Debug, clazz, msg, throwable); } private static void log(Level level, Class clazz, String msg, Throwable throwable) { String message = String.format("[%s] : %s", clazz, msg); switch (level) { case Info: logger.info(message, throwable); break; case Warn: logger.warn(message, throwable); break; case Error: logger.error(message, throwable); break; case Fatal: logger.fatal(message, throwable); break; default: case Debug: logger.debug(message, throwable); } } }