Log4j是用来记录日志的,项目中有用到,只是一直不太明白是如何配置的,最近花时间看了一下。
Log4j有三大组件:logger, appender and layout。这三个组件可以设置日志信息的类型、级别和格式。
一、Logger hierarchy
Loggers are named entities. Logger names are case-sensitive and they follow the hierarchical naming rule:
- 日志名称层次规则(Named Hierarchy)
- 若一个日志A的名称加’.'后是日志B名称的前缀,则称日志A是日志B的祖先。若日志A和日志B之间再无其他祖先日志,则称日志A是日志B的父日志。(A logger is said to be an ancestor of another logger if its name followed by a dot is a prefix of the descendant logger name. A logger is said to be a parent of a child logger if there are no ancestors between itself and the descendant logger.)
例如,名为”com.foo”的日志是名为”com.foo.bar”的日志的parent,类似的,”java”是”java.util”的parent,是”java.util.foo”的祖先。
根日志在整个层次的顶端,和其他日志相比,它有两个不同点:
1. 根日志一直存在
2. 不能通过名称获取,使用Logger.getRootLogger获取,其他日志使用Logger.getLogger获取,参数是日志名。
日志都有级别,如果一个日志没有级别,则从最近的拥有级别的祖先那里继承祖先的级别(If a given logger is not assigned a level, then it inherits one from its closest ancestor with an assigned level. )
- 日志级别继承规则(Level Inheritance)
- 日志C的级别与第一个在命名层次中级别非空的日志级别相同,从日志C开始,直至根日志。(The inherited level for a given logger C, is equal to the first non-null level in the logger hierarchy, starting at C and proceeding upwards in the hierarchy towards the
root logger.)
- 为了确保每个日志都有级别,根节点必须有级别。
-
| 日志名称 |
赋值级别 |
最终级别 |
| root |
Proot |
Proot |
| X |
Px |
Px |
| X.Y |
none |
Px |
| X.Y.Z |
Px.y.z |
Px.y.z |
调用日志实例的debug,info,warn,error,fatal,log方法来记日志,这些方法决定了当前记录日志的级别,如c是一个日志实例,c.info(“…”)是级别为INFO的写日志请求。
如果一个写日志请求的级别大于或等于这个日志的级别,那么这个写日志请求enabled,否则disabled。
- 写日志请求enabled规则(Basic Selection Rule)
- 日志A的级别为q(无论自身的还是继承来的),在日志A上的一个写日志请求的级别为p,若p>=q,则说此写日志请求enabled。(A log request of level p in a logger with (either assigned or inherited, whichever is appropriate) level q, is enabled if p >= q.)
|
这条规则是log4j的核心,级别都是有顺序的,对于标准级别,DEBUG < INFO < WARN < ERROR < FATAL。(This rule is at the heart of log4j. It assumes that levels are ordered. For the standard levels, we have DEBUG < INFO < WARN < ERROR < FATAL.)
例子:
// get a logger instance named “com.foo”
Logger logger = Logger.getLogger(“com.foo”);
// Now set its level. Normally you do not need to set the
// level of a logger programmatically. This is usually done
// in configuration files.
logger.setLevel(Level.INFO);
Logger barlogger = Logger.getLogger(“com.foo.Bar”);
// This request is enabled, because WARN >= INFO.
logger.warn(“Low fuel level.”);
// This request is disabled, because DEBUG < INFO.
logger.debug(“Starting search for nearest gas station.”);
// The logger instance barlogger, named “com.foo.Bar”,
// will inherit its level from the logger named
// “com.foo” Thus, the following request is enabled
// because INFO >= INFO.
barlogger.info(“Located nearest gas station.”);
// This request is disabled, because DEBUG < INFO.
barlogger.debug(“Exiting gas station search”);
用同一个日志名称调用getLogger方法得到的是同一个logger object的reference.
例如,
Logger x = Logger.getLogger("wombat");
Logger y = Logger.getLogger("wombat");
|
x and y refer to exactly the same logger object.
因此,不同传递日志引用就可以在其他地方得到一个日志的引用。在生物继承里,总是先parents后children,log4j可以配置为任何顺序,父日志如果在子日志后实例化,它依然能被找到而且处于正确的命名层次中。
二、Appenders and Layouts
1.Log4j可以将写日志的请求打印到不同的目的地,一个目的地就是一个appender。
2.一个日志可以有多个appender
- appender 叠加性(Appender Additivity)
- 日志C的会输出到所有C和C祖先的appender去,这就是appender 叠加性(The output of a log statement of logger C will go to all the appenders in C and its ancestors. This is the meaning of the term “appender additivity”.)
一 种例外,日志的C的祖先记为P,P将additivity位设为false,那么日志C输出到C和C的祖先一直到P(包括P)的appender里去,但 是不会输出到P祖先的appender里去。(However, if an ancestor of logger C, say P, has the additivity flag set to false, then C‘s output will be directed to all the appenders in C and it’s ancestors upto and including P but not the appenders in any of the ancestors of P.)
日志的additivity位默认为true(Loggers have their additivity flag set to true by default.)
|
例如:
Logger
Name |
Added
Appenders |
Additivity
Flag |
Output Targets |
Comment |
| root |
A1 |
not applicable |
A1 |
root没有默认的appender |
| x |
A-x1, A-x2 |
true |
A1, A-x1, A-x2 |
Appenders of “x” and root. |
| x.y |
none |
true |
A1, A-x1, A-x2 |
Appenders of “x” and root. |
| x.y.z |
A-xyz1 |
true |
A1, A-x1, A-x2, A-xyz1 |
Appenders in “x.y.z”, “x” and root. |
| security |
A-sec |
false |
A-sec |
No appender accumulation since the additivity flag is set to false. |
| security.access |
none |
true |
A-sec |
Only appenders of “security” because the additivity flag in “security” is set to false. |
通常不仅希望能够自定义输出的目的地,还希望自定义输出的格式,这个有appender的layout完成。layout负责格式化日志的格式以满足用户的愿望,appender负责将格式化好的日志输出到对应的目的地。
The PatternLayout, part of the standard log4j distribution, lets the user specify the output format according to conversion patterns similar to the C language printf function.
log4j.appender.appenderName.layout=org.apache.log4j.PatternLayout 配置日志信息的格式(布局)
Log4j提供的layout有以下几种:
org.apache.log4j.HTMLLayout(以HTML表格形式布局),
org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
log4j.appender. appenderName.layout.ConversionPattern=%d %p [%c] – <%m>%n 是设置打印格式格式化日志信息。
打印参数如下:
%m 输出代码中指定的消息
%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r 输出自应用启动到输出该log信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n”
%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
三、配置
log4j.rootCategory= [ level ] , appenderName, appenderName, … 是配置根Logger。
level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优 先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定 义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来,默认日志级别是ERROR;appenderName就是指定 Appender组件,确定日志输出目的地。如上例:log4j.rootCategory=info, stdout, logfile 配置根Logger的级别是INFO,日志输出的目的地是stdout, logfile。
log4j.appender. appenderName =org.apache.log4j.ConsoleAppender是配置日志信息输出目的地Appender。
Log4j提供的appender有以下几种:
org.apache.log4j.ConsoleAppender(控制台),
org.apache.log4j.FileAppender(文件),
org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件),
org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件),
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
log4j.properties简单例子:
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=debug,stdout
#只输出名为”org.ft” logger及其子logger的级别为WARN的日志
log4j.logger.org.ft=warn
参考:
http://logging.apache.org/log4j/1.2/manual.html
http://www.javaeye.com/topic/153732