问题描述
对于某些人来说,这可能是一个非常简单的问题,但我个人认为 Log4j 配置非常困难,而且学习进行脑部手术可能没有那么困难.
This might be a very easy question for some, but personally I find Log4j config to be nightmarishly difficult and that learning to perform brain surgery might be less challenging.
我试图让多个记录器登录不同的文件.这是我的 log4j.properties 文件中的内容:
I am trying to lave multiple loggers logging into different files.Here is what I have in my log4j.properties file:
# 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 应用程序:
And here is my (very simple) Java app used to test the config:
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);
:
One problem I always get an exception in the line 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)
第二个问题是两条消息都写入了两个日志.这是实际结果:
The 2nd problem is that both messages are written to both logs. Here is the actual result:
文件管理员:日志:
2014-04-27 11:55:30 INFO admin - hello admin
2014-04-27 11:55:30 INFO file - hello file
文件file.log:
File file.log:
2014-04-27 11:55:30 INFO admin - hello admin
2014-04-27 11:55:30 INFO file - hello file
这是必需的结果:
文件管理员:日志:
2014-04-27 11:55:30 INFO admin - hello admin
文件file.log:
File file.log:
2014-04-27 11:55:30 INFO file - hello file
导致异常的原因是什么,我怎样才能达到要求的结果?
What is causing the exception, and how can I achieve the required result?
推荐答案
Log4J 区分了负责生成日志消息的 loggers 和负责生成日志消息的 appenders负责将这些消息发送到某个地方(文件、控制台、数据库等).Logger 形成一个层次结构,根 logger 是名为 admin
的 logger 的父级,它是 admin.component1
等的父级,你可以将 appender 附加到任何层次结构中的记录器.默认情况下,记录器将向直接附加到它的所有附加程序或层次结构中的任何祖先发送消息(这就是为什么记录器通常命名为 Java 类的原因,例如,您可以控制 com.example 的日志记录.Class1
和 com.example.subpkg.AnotherClass
通过配置 com.example
记录器).
Log4J makes a distinction between loggers, which are responsible for generating log messages, and appenders, which are responsible for sending those messages somewhere (a file, the console, a database, etc.). Loggers form a hierarchy, the root logger is the parent of the logger named admin
, which is the parent of admin.component1
, etc., and you can attach appenders to any logger in the hierarchy. By default a logger will send messages to all appenders that are attached directly to it, or to any of its ancestors in the hierarchy (this is why loggers are conventionally named like Java classes, e.g. you can control logging for com.example.Class1
and com.example.subpkg.AnotherClass
by configuring the com.example
logger).
记录器和附加器形成独立的命名空间,这是您混淆的根源 - 名为 admin
的记录器和名为 admin
的附加器是两个独立的实体.
Loggers and appenders form separate namespaces and this is the source of your confusion - the logger named admin
and the appender named admin
are two separate entities.
您在问题中给出的配置定义了一个记录器(根记录器),它将它生成的所有消息发送到两个单独的 appender,一个用于两个文件中的每一个.然后您的代码请求两个不同的记录器,并为每个记录器生成一条日志消息.这两个记录器都从根记录器继承了 appender 配置,因此它们都将消息发送到两个已配置的 appender.
The configuration you have given in the question defines one logger (the root logger) which sends all the messages it generates to two separate appenders, one for each of the two files. Your code then requests two different loggers and generates one log message with each logger. Both these loggers inherit the appender configuration from the root logger, so they both send their messages to both of the configured appenders.
不是将两个 appender 附加到根记录器,您应该将 file
附加器附加到 file
记录器,将 admin
附加器附加到admin
记录器:
Instead of attaching the two appenders to the root logger, you should attach the file
appender to the file
logger and the admin
appender to the admin
logger:
log4j.rootLogger=INFO
log4j.logger.file=INFO, file
log4j.logger.admin=INFO, admin
这样 file
记录器只会将消息发送到 file.log
,admin
记录器只会发送到 admin.log
,并且来自其他记录器的所有消息都将被静默丢弃,因为没有附加到根的附加程序.
This way the file
logger will send messages only to file.log
, the admin
logger only to admin.log
, and all messages from other loggers will be silently discarded, as there are no appenders attached to the root.
additivity 标志是此规则的例外 - 将记录器的可加性设置为 false 基本上断开了从记录器到其父级的箭头,因此该记录器生成的消息(或从它的一个子节点)不会在树上再往上走,它们只会去直接附加到相关记录器的附加程序.
The additivity flag is the exception to this rule - setting a logger's additivity to false essentially disconnects the arrow from a logger up to its parent, so messages generated by that logger (or flowing into it from one of its children) will not go any further up the tree, they will only go to appenders attached directly to the logger in question.
这篇关于Log4j 配置 - 不同的日志到不同的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!