Log4j配置 - 将不同日志记录到不同文件

47

对于一些人来说可能很简单的问题,但是我个人认为Log4j配置非常困难,学习如何进行脑外科手术可能更少有挑战性。

我正在尝试让多个记录器记录到不同的文件中。 以下是我在log4j.properties文件中拥有的内容:

# Root logger option
log4j.rootLogger=INFO, file, admin

# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=/home/nick/logging/file.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

log4j.appender.admin=org.apache.log4j.RollingFileAppender
log4j.appender.admin.File=/home/nick/logging/admin.log
log4j.appender.admin.MaxFileSize=1MB
log4j.appender.admin.MaxBackupIndex=1
log4j.appender.admin.layout=org.apache.log4j.PatternLayout
log4j.appender.admin.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

这是我用来测试配置的(非常简单的)Java应用程序:

public static void main(String[] args) throws Exception {

    Properties resource = new Properties();
    InputStream in = new FileInputStream("/home/nick/logging/log4j.properties");
    resource.load(in);
    PropertyConfigurator.configure(resource);

    Logger admin = Logger.getLogger("admin");
    Logger file = Logger.getLogger("file");

    admin.info("hello admin");
    file.info("hello file");
}

我有两个问题:

一个问题是每次都在PropertyConfigurator.configure(resource);这一行抛出异常:

java.io.FileNotFoundException: /home/nick/logging (Is a directory)
 at java.io.FileOutputStream.open(Native Method)
 at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
 at java.io.FileOutputStream.<init>(FileOutputStream.java:136)
 at org.apache.log4j.FileAppender.setFile(FileAppender.java:289)
 at org.apache.log4j.RollingFileAppender.setFile(RollingFileAppender.java:167)
 at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:163)
 at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:256)

第二个问题是两条消息都被写入了两个日志文件。这是实际结果:

文件 admin:log:

2014-04-27 11:55:30 INFO  admin - hello admin
2014-04-27 11:55:30 INFO  file - hello file

文件 file.log:

2014-04-27 11:55:30 INFO  admin - hello admin
2014-04-27 11:55:30 INFO  file - hello file

这里是所需的结果:

文件 admin:log:

2014-04-27 11:55:30 INFO  admin - hello admin

文件 file.log:

2014-04-27 11:55:30 INFO  file - hello file

是什么导致了异常,我该如何实现所需的结果?


1
尝试使用相对路径 new FileInputStream("home/nick/logging/log4j.properties");。去掉第一个 / 以使其成为相对路径。 - Braj
其中最简单的解决方案在这里进行了说明。 - naeemgik
4个回答

127

Log4J区分记录器(loggers)和附加器(appenders),记录器负责生成日志消息,而附加器负责将这些消息发送到某个地方(文件、控制台、数据库等)。记录器形成一个层次结构,根记录器是名为admin的记录器的父记录器,admin.component1等都是它的子记录器,你可以将附加器附加到层次结构中的任何记录器上。默认情况下,记录器将发送消息到直接附加到它或其祖先记录器的所有附加器(这就是为什么记录器通常像Java类一样命名的原因,例如,你可以通过配置com.example记录器来控制com.example.Class1com.example.subpkg.AnotherClass的日志记录)。

记录器和附加器形成单独的名称空间,这是你困惑的原因——名为admin的记录器和名为admin的附加器是两个不同的实体。

问题中给出的配置定义了一个记录器(根记录器),它将生成的所有消息发送到两个不同的附加器,每个附加器对应一个文件。代码随后请求两个不同的记录器并生成一个日志消息。这两个记录器都继承自根记录器的附加器配置,因此它们都将它们的消息发送到这两个配置的附加器。

enter image description here

你应该将这两个附加器分别附加到file记录器和admin记录器而不是根记录器。

log4j.rootLogger=INFO
log4j.logger.file=INFO, file
log4j.logger.admin=INFO, admin

这样,file记录器将仅向file.log发送消息,admin记录器仅向admin.log发送消息,并且所有来自其他记录器的消息都将被静默丢弃,因为根记录器没有附加器。

enter image description here


additivity标志是此规则的例外-将记录器的可添加性设置为false基本上断开了从记录器到其父记录器的箭头,因此由该记录器生成的消息(或从其子记录器流入的消息)不会进一步向上移动,它们只会去往直接附加到相关记录器的附加器。


11
这是我见过的对于记录器最好的解释,非常有帮助。 - Tushar Banne
很好的解释。 - Lokesh Pandey
3
天啊!非常感谢@Ian Roberts。那太棒了。有人能把这个标记为已接受的答案吗??? - user2976594

23
回答自己的问题,这就是我所需要的:
log4j.logger.file=DEBUG, fileAppender
log4j.logger.admin=DEBUG, adminAppender

log4j.additivity.file=false
log4j.additivity.admin=false

log4j.appender.fileAppender=org.apache.log4j.RollingFileAppender
log4j.appender.fileAppender.File=/home/nick/logging/file.log
log4j.appender.fileAppender.MaxFileSize=1MB
log4j.appender.fileAppender.MaxBackupIndex=1
log4j.appender.fileAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

log4j.appender.adminAppender=org.apache.log4j.RollingFileAppender
log4j.appender.adminAppender.File=/home/nick/logging/admin.log
log4j.appender.adminAppender.MaxFileSize=1MB
log4j.appender.adminAppender.MaxBackupIndex=1
log4j.appender.adminAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.adminAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1} - %m%n

5

您不需要加载属性文件。只需将其放在src文件夹中,该文件夹将自动添加到类路径中。

示例代码:

public static void main(String[] args) throws Exception {

   Logger admin = Logger.getLogger("admin");
   Logger file = Logger.getLogger("file");

   admin.info("hello admin");
   file.info("hello file");
}

谢谢 - 在src文件中还有另一个log4j.properties,它正在使用那个,因此出现了异常。所以这个问题解决了。但是仍然存在两个消息都发送到两个文件的问题... - NickJ
请查看log4j-properties-examples - Braj
已经看过了。我基于“3. 输出到控制台和文件”的配置,但修改为两个不同的文件。 - NickJ
你的项目中有多个 log4j.properties 文件吗? - Braj

-1

首先:log4j建议使用xml格式文件来存储属性。

其次:最好在类加载器中加载属性文件。

第三:日志记录器中存在继承,但您可以通过添加属性来切断它,请参见log4j.properties文件-同一类中的多个记录器


不太理解那里发生了什么。 - NickJ
1
忘记第一和第二个,你已经有了答案,看看可加性。 - spopoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接