root类别位于logger继承结构的最上层,特性:
1)它一直存在.
(2)它不能根据名称而获得,调用类的静态方法Logger.getRootLogger获得.
所有的Logger可以通过静态方法Logger.getRootLogger获得而得到它们自己的实例.
Logger类的方法:
package org.apache.Log4j;
public class Logger {
// Creation & retrieval methods:
public static Logger getRootLogger();
public static Logger getLogger(String name);
// printing methods:
public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
// generic printing method:
public void log(Level l, Object message);
}
Loggers可以被分配级别,org.apache.Log4j.Level 类中定义了DEBUG,INFO,WARN,ERROR,FATAL级别的集合.
如果一个Logger没有被分配一个级别,那么它将从离它最近一个被分配了级别的ancestor那里继承.
Logger的输出的实例方法之一实现日志的请求.输出的方法有:debug,info,warn,error,fatal和log.
通过定义输出方法区分日志的请求的级别.如果C是一个Logger的实例,那么声明C.info("....")就是一个INFO级别的日志请求.如果一个日志的请求的级别高于或等于日志的级别那么它就能被启用,反之将被禁用.
对于标准级别的大小关系:DEBUG<INFO<WARN<ERROR<FATAL
//取得名为com.foo的实例:
Logger logger = Logger.getLogger("com.foo");
//设置它的级别:
cat.setLevel(Level.INFO); //一般都是通过配置文件来设置的.
//barlogger继承了logger
Logger barlogger = Logger.getLogger("com.foo.Bar");
//这个请求可用,因为WARN >= INFO
logger.warn("Low fuel level.");
//这个请求不可用,因为: DEBUG < INFO.
logger.debug("Starting search for nearest gas station.");
//下面请求也为可用
barlogger.info("Located nearest gas station.");
可以调用getLogger方法将返回一个同名的Logger对象的实例.
Categoty x = Logger.getLogger("wombat")
Categoty y = Logger.getLogger("wombat")
x和y参照的是同一个Logger对象.
这样我们就可以先定义一个Logger.然后在代码的其它地方不需要传参就可以重新得到我们已经定义的Logger的实例.
Log4j的loggers可以在任何顺序创造和配置,特别是,一个后实例化的"parent"logger能够找到并且连接它的子logger.
log4j通过软件组件命名logger:
可以通过logger的静态的初始化方法在每一个类里定义一个logger,令logger的名字等于类名的全局名,而实现logger的命名,Log4j命名没有限制.这样做能对日志中的信息精确的定位.
一个logger可以设置超过一个的appender这样可以允许日志请求被输出到输出源.
可以用addAppender方法添加一个appender到一个给定的logger.
一个logger继承另一个logger时也将父辈的appender继承过来了.
我们也可以通过设置appender的additivity flag 为false,来重载appender的默认行为,以便继承的属性不在生效,但它的子类仍会继承它的属性.
配置日志信息输出目的地Appender,其语法为:
log4j.appender.appenderName = fully.qualified.name.of.appender.class log4j.appender.appenderName.option1 = value1
...
log4j.appender.appenderName.option = valueN
其中,Log4j提供的appender有以下几种的输出目的地:
org.apache.log4j.ConsoleAppender,将日志信息输出到控制台
org.apache.log4j.FileAppender,将日志信息输出到一个文件
org.apache.log4j.DailyRollingFileAppender,将日志信息输出到一个,并且每天输出到一个新的日志文件,
按照不同的配置可以定义每月一个日志文件,或者每周,每天,每小时,每分钟等输出一个新的日志文件。
org.apache.log4j.RollingFileAppender,将日志信息输出到一个文件,通过指定文件的的尺寸,当文件大小到达指定尺寸的时候会自动把文件改名,如名为example.log的文件会改名为example.log.1,同时产生一个新的example.log文件。如果新的文件再次达到指定尺寸,又会自动把文件改名为example.log.2,同时产生一个example.log文件。依此类推,直到example.log. MaxBackupIndex,MaxBackupIndex的值可在配置文件中定义。
org.apache.log4j.WriterAppender,将日志信息以流格式发送到任意指定的地方。
org.apache.log4j.jdbc.JDBCAppender,通过JDBC把日志信息输出到数据库中。
org.apache.log4j.net.SMTPAppender,将日志信息以邮件的方式发送到指定的邮箱。
logger C的一个祖先logger P,它的附加标志被设为false(默认为true),那么C的输出将被定位到所有C的appender,以及从开始上溯到P的所有ancestor logger的appender.
注意:P的appender会被定位.
layout用来定义appender的输出格式:
PatternLayout,作为Log4j标准版中的一部分让用户类似C语言的printf方法的格式来输出.
转化模式为"%r [%t] %-5p %c - %m%n"的PatternLayout将输出类似如下的信息:
176 [main] INFO org.foo.Bar - Located nearest gas station.
第一个栏位是程序开始后消逝的毫秒数.
第二个栏位是做出日志的线程.
第三个栏位是log的级别.
第四个栏位是日志请求相关的logger的名字.-后是文字的信息的表述.
Log4j将根据用户定义的公式来修饰日志信息的内容.例如你经常需要记录Oranges,一个在你当前的项目被用到的对象类型,那么你可以注册一个OrangeRenderer,它将在一个orange需要被记录时被调用.
对象渲染类似类的结构继承,例如oranges的一个实例fruits,如果你注册一个FruitReanderer,所有的水果包括oranger将被FruitReanderer所渲染.除非你注册了一个orange.
注意:对象渲染必须实现ObjectRenderer接口.
配置日志信息的格式(布局),其语法为:
log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
log4j.appender.appenderName.layout.option1 = value1
...
log4j.appender.appenderName.layout.option = valueN
其中Log4j提供layout 有以下几种:
org.apache.log4j.HTMLLayoutHTML (以HTML表格形式布局)
org.apache.log4j.PatternLayout (可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout (包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout (包含日志产生的时间,线程,类别等等信息)
Log4J 采用C语言中的 printf 函数的打印格式化日志信息
%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 月 1 8日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名,发生的线程,以用在代码中的行数.举例:Testlog4.main(TestLog4.java:10)
%F输出日志事件的发生文件名.
%L输出日志事件的发生行数.
这里是一个非常简单的例子,程序实现了 HTMLLayout和WriterAppender:
import java.io.*;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.HTMLLayout;
import org.apache.log4j.WriterAppender;
public class htmlandwrite {
static Logger logger = Logger.getLogger(htmlandwrite.class);
public static void main(String args[]) {
HTMLLayout layout = new HTMLLayout();
WriterAppender appender = null;
try {
FileOutputStream output = new FileOutputStream("output2.html");
appender = new WriterAppender(layout,output);
} catch(Exception e) {}
logger.addAppender(appender);
logger.setLevel((Level) Level.DEBUG);
logger.debug("Here is some DEBUG");
logger.info("Here is some INFO");
logger.warn("Here is some WARN");
logger.error("Here is some ERROR");
logger.fatal("Here is some FATAL");
}
}
输出结果:
package cn.Log4j; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.ConsoleAppender; public class ConsandPatt { static Logger logger = Logger.getLogger(ConsandPatt.class); public static void main(String args[]) { // Note, %n is newline String pattern = "Milliseconds since program start: %r %n"; pattern += "Classname of caller: %C %n"; pattern += "Date in ISO8601 format: %d{ISO8601} %n"; pattern += "Location of log event: %l %n"; pattern += "Message: %m %n %n"; PatternLayout layout = new PatternLayout(pattern); ConsoleAppender appender = new ConsoleAppender(layout); logger.addAppender(appender); logger.setLevel((Level) Level.DEBUG); logger.debug("Here is some DEBUG"); logger.info("Here is some INFO"); logger.warn("Here is some WARN"); logger.error("Here is some ERROR"); logger.fatal("Here is some FATAL"); } } |
执行结果: Milliseconds since program start: 0 Classname of caller: cn.Log4j.ConsandPatt Date in ISO8601 format: 2008-01-12 06:00:46,765 Location of log event: cn.Log4j.ConsandPatt.main(ConsandPatt.java:38) Message: Here is some DEBUG
Milliseconds since program start: 0 Classname of caller: cn.Log4j.ConsandPatt Date in ISO8601 format: 2008-01-12 06:00:46,765 Location of log event: cn.Log4j.ConsandPatt.main(ConsandPatt.java:40) Message: Here is some INFO
Milliseconds since program start: 0 Classname of caller: cn.Log4j.ConsandPatt Date in ISO8601 format: 2008-01-12 06:00:46,765 Location of log event: cn.Log4j.ConsandPatt.main(ConsandPatt.java:42) Message: Here is some WARN
Milliseconds since program start: 0 Classname of caller: cn.Log4j.ConsandPatt Date in ISO8601 format: 2008-01-12 06:00:46,765 Location of log event: cn.Log4j.ConsandPatt.main(ConsandPatt.java:44) Message: Here is some ERROR
Milliseconds since program start: 16 Classname of caller: cn.Log4j.ConsandPatt Date in ISO8601 format: 2008-01-12 06:00:46,781 Location of log event: cn.Log4j.ConsandPatt.main(ConsandPatt.java:46) Message: Here is some FATAL |
用配置文件来配置Log4j:
现在Log4j支持XML和java properties(key=value)文件下几种格式.
XML:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender"> <layout class="org.apache.log4j.SimpleLayout"/> </appender> <root> <priority value ="debug" /> <appender-ref ref="ConsoleAppender"/> </root> </log4j:configuration> |
文件以标准的XML声明作为开始,后面跟着指出DTD(文档类型定义)的DOCTYPE声明,它定义了XML文件的结构,例如,什么元素可以嵌入在其他元 素中等等。上面文件在log4j发行版的src/java/org/apache/log4j/xml目录中。 接着看看封装所有元素的 log4j:configuration 元素,它在DOCTYPE声明中被指定为根元素。 这里创建一个名叫"ConsoleAppender"的 Appender,注意,你可以选择任何名字,该示例之所以选择"ConsoleAppender",完全是为了示例的设计。接着这个appender类 以全名形式给出,经常用规范(fully qualified)类名。 Appender必须具有一个指定的 name和class。嵌入在 Appender之内的是 layout元素,这里它被指定为SimpleLayout。 Layout 必须具有一个 class属性。 root元素必须存在且不能被子类化。示例中的优先级被设置为"debug",设置appender饱含一个appender-ref元素。还有更多的属 性或元素可以指定。查看log4j发行版中的src/java/org/apache/log4j/xml/log4j.dtd以了解关于XML配置文件 结构的更多信息。可以用下面这种方法把配置信息文件读入到Java程序中: DOMConfigurator.configure("configurationfile.xml");
DOMConfigurator 用一棵DOM树来初始化log4j环境。这里是示例中的XML配置文件:plainlog4jconfig.xml。这里是执行该配置文件的程序: files/externalxmltest.java: |
这里是一个实现带有PatternLayout的FileAppender的日志记录器Logger的XML配置文件: <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="appender" class="org.apache.log4j.FileAppender"> <param name="File" value="Indentify-Log.txt"/> <param name="Append" value="false"/> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d [%t] %p - %m%n"/> </layout> </appender> <root> <priority value ="debug"/> <appender-ref ref="appender"/> </root> </log4j:configuration> |
java properties(key=value)文件:
假定有一个用了Log4j和程序MyApp. import com.foo.Bar; // Import Log4j 相关类. import org.apache.Log4j.Logger; import org.apache.Log4j.BasicConfigurator; public class MyApp { // Define a static logger variable so that it references the // Logger instance named "MyApp". static Logger logger = Logger.getLogger(MyApp.class); public static void main(String[] args) { // 创建了一个相当简单的Log4j设置,加入一个ConsoleAppender 到根logger,默认采用输出格式:"%-4r [%t] %-5p %c %x - %m%n". BasicConfigurator.configure(); logger.info("Entering application."); Bar bar = new Bar(); bar.doIt(); logger.info("Exiting application."); } 调用的类: package com.foo; import org.apache.Log4j.Logger; public class Bar { static Logger logger = Logger.getLogger(Bar.class); //继承自根的logger默认被分配了Level.DEBUG的级别. public void doIt() { logger.debug("Did it again!"); } } 输出为: 0 [main] INFO Log4jTest - Entering application. 0 [main] DEBUG Bar - Did it again! 0 [main] INFO Log4jTest - Exiting application. MyApp类配置Log4j是通过调用BasicConfigurator.configure方法.其它的类仅仅需要引入org.apache.Log4j.Logger 类找到它们希望用的 logger 并用它就行了. |
为了方便日志输出可以在运行时刻被控制.这里提供一个小小修改的版本:
import com.foo.Bar;
import org.apache.Log4j.Logger;
import org.apache.Log4j.PropertyConfigurator;
public class MyApp {
static Logger logger = Logger.getLogger(MyApp.class.getName());
public static void main(String[] args) {
// BasicConfigurator replaced with PropertyConfigurator.
PropertyConfigurator.configure(args[0]);
logger.info("Entering application.");
Bar bar = new Bar();
bar.doIt();
logger.info("Exiting application.");
}
}
修改后的MyApp通知程序调用PropertyConfigurator()方法解析一个配置文件,并用根据这个配置文件来设置日志.
配置文件内容:
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# Print the date in ISO 8601 format
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
# Print only messages of level WARN or above in the package com.foo.
log4j.logger.com.foo=WARN
打印结果:
2008-01-11 14:01:07,500 [main] INFO cn.Log4j.Log4jTest - Entering application.
2008-01-11 14:01:07,515 [main] DEBUG cn.Log4j.Bar - Did it again!
2008-01-11 14:01:07,515 [main] INFO cn.Log4j.Log4jTest - Exiting application.
另一个配置文件,它使用了多个appenders.
log4j.rootLogger=debug,stdout,R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%5p[%t](%F:%L)-%m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
#输出到你项目所属的目录下,如果文件已满则旧的example.log 被命名为example.log.1中.
log4j.appender.R.File=example.log
log4j.appender.FILE.Encoding=GBK
log4j.appender.R.MaxFileSize=100KB
# Keep one backup file
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x -
%m%n
注意:我们不需要重新编译代码就可以获得这些不同的日志行为.它可以适应输出到不同的系统,或者转发日志到一个远程的log4j服务器.它根据本地server的策略来进程日志输出.
在避免日志被禁用时产生不必要的花费,输出日志时要注意这样写:
if(logger.isDebugEnabled() { //判断Debut是否可用
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}