您的位置:首页 > 其它

Log4j 使用简介(转了又转)

2006-07-18 15:37 453 查看
1.简介
程序开发环境中的日志记录是由嵌入在程序中以输出一些对开发人员有用信息的语句所组成。例如,跟踪语句(trace),结构转储和常见的System.out.println或printf调试语句。log4j提供分级方法在程序中嵌入日志记录语句。日志信息具有多种输出格式和多个输出级别。
使用一个专门的日志记录包,可以减轻对成千上万的System.out.println语句的维护成本,因为日志记录可以通过配置脚本在运行时得以控制。log4j维护嵌入在程序代码中的日志记录语句。通过规范日志记录的处理过程,一些人认为应该鼓励更多的使用日志记录并且获得更高程度的效率。
2.快速入门
在深入介绍log4j之前我们先来看一段代码,对log4j有一个初步的了解,代码如下:
创建一个类,代码如下:
packageTestLog4j;
importorg.apache.log4j.Logger;
importorg.apache.log4j.BasicConfigurator;
importorg.apache.log4j.PropertyConfigurator;
importorg.apache.log4j.Priority;;

publicclassTestLog4j
{
//代码(1)
staticLoggerlogger=Logger.getLogger(TestLog4j.class.getName());
publicTestLog4j(){}
publicstaticvoidmain(String[]args)
{
//代码(2)
BasicConfigurator.configure();
//代码(3)
logger.debug("Startofthemain()inTestLog4j");
logger.info("JusttestingalogmessagewithprioritysettoINFO");
logger.warn("JusttestingalogmessagewithprioritysettoWARN");
logger.error("JusttestingalogmessagewithprioritysettoERROR");
logger.fatal("JusttestingalogmessagewithprioritysettoFATAL");
logger.log(Priority.DEBUG,"Testingalogmessageuseaalternateform");
logger.debug("Endofthemain()inTestLog4j");
}
}

最后运行这个类,你就会看到运行结果为:
0[main]DEBUGTestLog4j.TestLog4j-Startofthemain()inTestLog4j
10[main]INFOTestLog4j.TestLog4j-JusttestingalogmessagewithprioritysettoINFO
10[main]WARNTestLog4j.TestLog4j-JusttestingalogmessagewithprioritysettoWARN
21[main]ERRORTestLog4j.TestLog4j-JusttestingalogmessagewithprioritysettoERROR
21[main]FATALTestLog4j.TestLog4j-JusttestingalogmessagewithprioritysettoFATAL
111[main]DEBUGTestLog4j.TestLog4j-Testingalogmessageuseaalternateform
111[main]DEBUGTestLog4j.TestLog4j-Endofthemain()inTestLog4j

首先解释一下上面输出结果的意义。第一个数字是指程序开始运行到运行该日志语句所经历的毫秒数(用来做一点运行效率分析也不错),“[main]”是日志事件发生的线程,随后的“DEBUG”、“INFO”等信息是相应日志信息的优先级别,“TestLog4”是当前Logger的实例名,最后是日志信息。
在这段程序中,使用了Log4J提供的一个基本配置类BasicConfigurator对Log4J进行初始化。但在实际使用时通常不这么做,因为这多少有点“硬”编码。今后如果要修改Log4J的配置,就需要修改、重新编译代码,这通常不是大家所希望的。通常,我们都提供一个名为log4j.properties的文件,在第一次调用到Log4J时,Log4J会在类路径中定位这个文件,并读入这个文件完成的配置。这个配置文件告诉Log4J以什么样的格式、把什么样的信息、输出到什么地方。我们来看一个简单的log4j.properties配置文件的示例,代码如下:
log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern="%-4r[%t]%-5p%c%x-%m%n

把上面的内容存储为log4j.properties,并放到和TestLog4J.class同一目录下(当然也可以放到其它任何目录,只要该目录被包含到类路径中即可)。具体这些配置文件中每行的意义,在以后章节会有详细的说明,现在可以先跳过。现在你可以注释掉上面程序中的“BasicConfigurator.configure();语句,然后使用[b]log4j.properties属性文件完成Log4J的配置,重新编译、运行,就得到和上面一样的结果。[/b]”
这样做有什么好处呢?现在就初步领略一些Log4J的灵活、强大功能。比如系统要上线了,希望输出一些警告和错误信息,这时仅需要修改log4j.properties文件中的“log4j.rootCategory=DEBUG,A1”即可,然后设置日志输出的最低级别是WARN,设置为“log4j.rootCategory=WARN,A1”。此时不需要修改任何代码,重新运行系统,输出结果就变成了:
20[main]WARNTestLog4J-JusttestingalogmessagewithprioritysettoWARN
30[main]ERRORTestLog4J-JusttestingalogmessagewithprioritysettoERROR
30[main]FATALTestLog4J-JusttestingalogmessagewithprioritysettoFATAL
3.安装
为了使用我们即将要安装的日志记录工具,还必须要设置操作环境,只有这样,工具才能知道从哪里找到它所需要的信息,并且操作系统知道从哪里找到这个工具。那么,怎样做呢?实际上,它要求更改操作环境。我有一些这方面的资格文档。ConfiguringAWindowsWorkingEnvironment和ConfiguringAUnixWorkingEnvironment.
1.从http://jakarta.apache.org/log4j/docs/download.html下载log4j发行版。
2.解压存档文件到合适的目录中。
3.添加文件dist/lib/log4j-1.2.6.jar到CLASSPATH环境变量中。
4.log4j的基本概念
使用log4j大概涉及3个主要概念:
1.公共类Logger
Logger负责处理日志记录的大部分操作。
2.公共接口Appender
Appender负责控制日志记录操作的输出。
3.公共抽象类Layout
Layout负责格式化Appender的输出。
4.1.Logger
日志记录器(Logger)是日志处理的核心组件。log4j具有5种正常级别(Level)。日志记录器(Logger)的可用级别Level(不包括自定义级别Level),以下内容就是摘自log4jAPI(http://jakarta.apache.org/log4j/docs/api/index.html):
·staticLevelDEBUG
DEBUGLevel指出细粒度信息事件对调试应用程序是非常有帮助的。
·staticLevelINFO
INFOlevel表明消息在粗粒度级别上突出强调应用程序的运行过程。
·staticLevelWARN
WARNlevel表明会出现潜在错误的情形。
·staticLevelERROR
ERRORlevel指出虽然发生错误事件,但仍然不影响系统的继续运行。
·staticLevelFATAL
FATALlevel指出每个严重的错误事件将会导致应用程序的退出。
另外,还有两个可用的特别的日志记录级别:(以下描述来自log4jAPIhttp://jakarta.apache.org/log4j/docs/api/index.html):
·staticLevelALL
ALLLevel是最低等级的,用于打开所有日志记录。
·staticLevelOFF
OFFLevel是最高等级的,用于关闭所有日志记录。
日志记录器(Logger)的行为是分等级的
ALL(最低等级)<DEBUG<INFO<WARN<ERROR<FATAL<OFF(最高等级)
引入级别后就可通过修改调试的级别来控制某个调试信息是否输出。假设我们有的信息是在开发时才需要输出的(称为测试信息),那么我们把输出测试信息的Logger的级别在开发时设为DEBUG级别的,并用debug(Objectmessage)函数来进行打印。当要发布系统时,只需把相应的Logger的级别调高就可以屏蔽掉测试信息。

.日志输出等级
日志记录器(Logger)将只输出那些级别高于或等于它的级别的信息。如果没有设置日志记录器(Logger)的级别,那么它将会继承最近的祖先的级别。因此,如果在包com.foo.bar中创建一个日志记录器(Logger)并且没有设置级别,那它将会继承在包com.foo中创建的日志记录器(Logger)的级别。如果在com.foo中没有创建日志记录器(Logger)的话,那么在com.foo.bar中创建的日志记录器(Logger)将继承root日志记录器(Logger)的级别,root日志记录器(Logger)经常被实例化而可用,它的级别为DEBUG。
有很多方法可以创建一个日志记录器(Logger),下面方法可以取回root日志记录器:

Loggerlogger=Logger.getRootLogger();

还可以这样创建一个新的日志记录器:

Loggerlogger=Logger.getLogger("MyLogger");

比较常用的用法,就是根据类名实例化一个静态的全局日志记录器:

staticLoggerlogger=Logger.getLogger(test.class);

所有这些创建的叫"logger"的日志记录器都可以用下面方法设置级别:

logger.setLevel((Level)Level.WARN);

可以使用7个级别中的任何一个;Level.DEBUG,Level.INFO,Level.WARN,Level.ERROR,Level.FATAL,Level.ALLandLevel.OFF.
4.2.Appender
Appender控制日志怎样输出。下面列出一些可用的Appender(log4jAPI中所描述的http://jakarta.apache.org/log4j/docs/api/index.html):
1.ConsoleAppender:使用用户指定的布局(layout)输出日志事件到System.out或者System.err。默认的目标是System.out。
2.DailyRollingFileAppender扩展FileAppender,因此多个日志文件可以以一个用户选定的频率进行循环日志记录。
3.FileAppender把日志事件写入一个文件
4.RollingFileAppender扩展FileAppender备份容量达到一定大小的日志文件。
5.WriterAppender根据用户的选择把日志事件写入到Writer或者OutputStream。
6.SMTPAppender当特定的日志事件发生时,一般是指发生错误或者重大错误时,发送一封邮件。
7.SocketAppender给远程日志服务器(通常是网络套接字节点)发送日志事件(LoggingEvent)对象。
8.SocketHubAppender给远程日志服务器群组(通常是网络套接字节点)发送日志事件(LoggingEvent)对象。
9.SyslogAppender给远程异步日志记录的后台精灵程序(daemon)发送消息。
10.TelnetAppender一个专用于向只读网络套接字发送消息的log4jappender。
还可以实现Appender接口,创建以自己的方式进行日志输出的Appender。
4.2.1.使用ConsoleAppender
ConsoleAppender可以用这种方式创建:

ConsoleAppenderappender=newConsoleAppender(newPatternLayout());

创建了一个控制台appender,具有一个默认的PatternLayout。它使用了默认的System.out输出。
4.2.2.使用FileAppender
FileAppender可以用这种方式创建:

FileAppenderappender=null;


try{


appender=newFileAppender(newPatternLayout(),"filename");


}catch(Exceptione){}



上面用到的构造函数:

FileAppender(Layoutlayout,Stringfilename)


实例化一个FileAppender并且打开变量"filename"指定的文件。



另一个有用的构造函数是:

FileAppender(Layoutlayout,Stringfilename,booleanappend)


实例化一个FileAppender并且打开变量"filename"指定的文件。



这个构造函数还可以选择是否对指定的文件进行追加的方式输出。如果没有指定值,那么默认的方式就是追加。
4.2.3.使用WriterAppender
WriterAppender可以用这种方式创建:

WriterAppenderappender=null;


try{


appender=newWriterAppender(newPatternLayout(),newFileOutputStream("filename"));


}catch(Exceptione){}



这个WriterAppender使用的构造函数带有PatternLayout和OutputStream参数,在这种情况下,FileOutputStream用于向一个文件输出。当然,它还具有其他可用的构造函数。
4.3.Layout
4.3.1简介
Appender必须使用一个与之相关联的Layout,这样它才能知道怎样格式化它的输出。当前,log4j具有三种类型的Layout:
1.HTMLLayout格式化日志输出为HTML表格。
2.PatternLayout根据指定的转换模式格式化日志输出,或者如果没有指定任何转换模式,就使用默认的转换模式。
3.SimpleLayout以一种非常简单的方式格式化日志输出,它打印级别Level,然后跟着一个破折号“-“,最后才是日志消息。
4.3.2打印参数
Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数见如下表:
%m输出代码中指定的消息
%p输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
%r输出自应用启动到输出该log信息耗费的毫秒数
%c输出所属的类目,通常就是所在类的全名
%t输出产生该日志事件的线程名
%n输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n”
%d输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyMMMddHH:mm:ss,SSS},输出类似:2002年10月18日22:10:28,921
%l输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
4.4.基本示例
4.4.1.SimpleLayout和FileAppender
这里是一个非常简单的例子,程序实现了SimpleLayout和FileAppender:

importorg.apache.log4j.Level;


importorg.apache.log4j.Logger;


importorg.apache.log4j.SimpleLayout;


importorg.apache.log4j.FileAppender;


publicclasssimpandfile{


staticLoggerlogger=Logger.getLogger(simpandfile.class);


publicstaticvoidmain(Stringargs[]){


SimpleLayoutlayout=newSimpleLayout();


FileAppenderappender=null;


try{


appender=newFileAppender(layout,"output1.txt",false);


}catch(Exceptione){}


logger.addAppender(appender);


logger.setLevel((Level)Level.DEBUG);


logger.debug("HereissomeDEBUG");


logger.info("HereissomeINFO");


logger.warn("HereissomeWARN");


logger.error("HereissomeERROR");


logger.fatal("HereissomeFATAL");


}


}



你可以下载:simpandfile.java。还可以查看它的输出:output1.txt.
4.4.2.HTMLLayout和WriterAppender
这里是一个非常简单的例子,程序实现了HTMLLayout和WriterAppender:

importjava.io.*;


importorg.apache.log4j.Level;


importorg.apache.log4j.Logger;


importorg.apache.log4j.HTMLLayout;


importorg.apache.log4j.WriterAppender;


publicclasshtmlandwrite{


staticLoggerlogger=Logger.getLogger(htmlandwrite.class);


publicstaticvoidmain(Stringargs[]){


HTMLLayoutlayout=newHTMLLayout();


WriterAppenderappender=null;


try{


FileOutputStreamoutput=newFileOutputStream("output2.html");


appender=newWriterAppender(layout,output);


}catch(Exceptione){}


logger.addAppender(appender);


logger.setLevel((Level)Level.DEBUG);


logger.debug("HereissomeDEBUG");


logger.info("HereissomeINFO");


logger.warn("HereissomeWARN");


logger.error("HereissomeERROR");


logger.fatal("HereissomeFATAL");


}


}



你可以下载:simpandfile.java.还可以查看它的输出:output1.txt.
4.4.3.PatternLayout和ConsoleAppender
这里是一个非常简单的例子,程序实现了PatternLayout和ConsoleAppender:

importorg.apache.log4j.Level;


importorg.apache.log4j.Logger;


importorg.apache.log4j.PatternLayout;


importorg.apache.log4j.ConsoleAppender;


publicclassconsandpatt{


staticLoggerlogger=Logger.getLogger(consandpatt.class);


publicstaticvoidmain(Stringargs[]){


//Note,%nisnewline


Stringpattern="Millisecondssinceprogramstart:%r%n";


pattern+="Classnameofcaller:%C%n";


pattern+="DateinISO8601format:%d{ISO8601}%n";


pattern+="Locationoflogevent:%l%n";


pattern+="Message:%m%n%n";




PatternLayoutlayout=newPatternLayout(pattern);


ConsoleAppenderappender=newConsoleAppender(layout);


logger.addAppender(appender);


logger.setLevel((Level)Level.DEBUG);


logger.debug("HereissomeDEBUG");


logger.info("HereissomeINFO");


logger.warn("HereissomeWARN");


logger.error("HereissomeERROR");


logger.fatal("HereissomeFATAL");


}


}



你可以下载:simpandfile.java.还可以查看它的输出:output2.txt.
5.实例对比
看一个简单的例子,它是一个用Java实现的客户/服务器网络程序。刚开始我们不使用Log4j,而是使用了一系列的打印语句,然后我们将使用Log4j来实现它的日志功能。这样,大家就可以清楚地比较出前后两个代码的差别。

不使用log4j的客户程序

packagelog4j;

importjava.io.*;
importjava.net.*;

/**
*
*<p>ClientWithoutLog4j</p>
*<p>Description:asamplewithlog4j</p>
*@version1.0
*/
publicclassClientWithoutLog4j{

/**
*
*@paramargs
*/
publicstaticvoidmain(Stringargs[]){

Stringwelcome=null;
Stringresponse=null;
BufferedReaderreader=null;
PrintWriterwriter=null;
InputStreamin=null;
OutputStreamout=null;
Socketclient=null;

try{
client=newSocket("localhost",8001);
System.out.println("info:Clientsocket:"+client);
in=client.getInputStream();
out=client.getOutputStream();
}catch(IOExceptione){
System.out.println("error:IOException:"+e);
System.exit(0);
}

try{
reader=newBufferedReader(newInputStreamReader(in));
writer=newPrintWriter(newOutputStreamWriter(out),true);

welcome=reader.readLine();
System.out.println("debug:Serversays:'"+welcome+"'");

System.out.println("debug:HELLO");
writer.println("HELLO");
response=reader.readLine();
System.out.println("debug:Serverresponds:'"+response+"'");

System.out.println("debug:HELP");
writer.println("HELP");
response=reader.readLine();
System.out.println("debug:Serverresponds:'"+response+"'");

System.out.println("debug:QUIT");
writer.println("QUIT");
}catch(IOExceptione){
System.out.println("warn:IOExceptioninclient.in.readln()");
System.out.println(e);
}
try{
Thread.sleep(2000);
}catch(Exceptionignored){}
}
}

迁移到Log4j客户程序

packagelog4j;

importjava.io.*;
importjava.net.*;

//addforlog4j:importsomepackage
importorg.apache.log4j.PropertyConfigurator;
importorg.apache.log4j.Logger;
importorg.apache.log4j.Level;

/**
*
*<p>ClientWithLog4j</p>
*<p>Description:asamplewithlog4j</p>
*@version1.0
*/
publicclassClientWithLog4j{

/*
addforlog4j:classLoggeristhecentralclassinthelog4jpackage.
wecandomostloggingoperationsbyLoggerexceptconfiguration.
getLogger(...):retrievealoggerbyname,ifnotthencreateforit.
*/
staticLoggerlogger=Logger.getLogger
(ClientWithLog4j.class.getName());

/**
*
*@paramargs:configurationfilename
*/
publicstaticvoidmain(Stringargs[]){

Stringwelcome=null;
Stringresponse=null;
BufferedReaderreader=null;
PrintWriterwriter=null;
InputStreamin=null;
OutputStreamout=null;
Socketclient=null;

/*
addforlog4j:classBasicConfiguratorcanquicklyconfigurethepackage.
printtheinformationtoconsole.
*/
BasicConfigurator.configure();

//addforlog4j:setthelevel
//logger.setLevel((Level)Level.DEBUG);

try{
client=newSocket("localhost",8001);

//addforlog4j:logamessagewiththeinfolevel
logger.info("Clientsocket:"+cli
ent);
in=client.getInputStream();
out=client.getOutputStream();
}catch(IOExceptione){

//addforlog4j:logamessagewiththeerrorlevel
logger.error("IOException:"+e);

System.exit(0);
}

try{
reader=newBufferedReader(newInputStreamReader(in));
writer=newPrintWriter(newOutputStreamWriter(out),true);

welcome=reader.readLine();

//addforlog4j:logamessagewiththedebuglevel
logger.debug("Serversays:'"+welcome+"'");

//addforlog4j:logamessagewiththedebuglevel
logger.debug("HELLO");

writer.println("HELLO");
response=reader.readLine();

//addforlog4j:logamessagewiththedebuglevel
logger.debug("Serverresponds:'"+response+"'");

//addforlog4j:logamessagewiththedebuglevel
logger.debug("HELP");

writer.println("HELP");
response=reader.readLine();

//addforlog4j:logamessagewiththedebuglevel
logger.debug("Serverresponds:'"+response+"'");

//addforlog4j:logamessagewiththedebuglevel
logger.debug("QUIT");

writer.println("QUIT");
}catch(IOExceptione){

//addforlog4j:logamessagewiththewarnlevel
logger.warn("IOExceptioninclient.in.readln()");

System.out.println(e);
}
try{
Thread.sleep(2000);
}catch(Exceptionignored){}
}
}
至此关于log4j的大体概况就讲述到这种水平,相信大家都已经对他有所了解了,如果你还想更深的了解log4j,请经常访问下面提及的相关链接:
Log4j项目主页………………………………………………….www.log4j.org
Log4jFAQ……………………………………………………….www.log4j.org/log4j/faq.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: