一.简介:
为了更好地监视代码中变量的变化和跟踪代码的运行轨迹,同时充当开发环境中的调试器。Apache通用日志包是Apache组织的开源项目,负责向开发者提供一系列通用的日志Nooplog接口。用户可以自由地选择和实现通用日志接口。通用日志目前主要支持以下几个日志器:
1. Log4j:是第三方软件,由Logger、Appender、Layout三个组件组成。
2. SimpleLog:在通用日志包中自带了org.apache.commons.logging.impl.SimpleLog日志实现类。它实现了Log接口,把日志消息都输出到系统错误流System.err中。
3. NoOpLog:在通用日志包中自带了org.apache.commons.logging.impl.NoOpLog日志实现类。它实现了Log接口,其输出日志的方法中不进行任何操作。
Log4J是Log4家族的员,Log4家族包挂:看4之后的字母都知道这是给哪种环境而开发的API。其中我们要介绍的Log4j当然就是针对Java而开发的API了。
Log4家族 | |
Log4C | 适合C |
Log4CPlus/Log4cpp | 适合C++ |
Log4j | 适合Java |
Log4Net | 适合DOTNet |
Log4Perl | 适合Perl |
Log4PHP | 适合PHP |
Log4PLSQL | 适合PL/SQL |
Log4LS | 适合LotusScript |
Log4py/Log4p | 适合python |
qmmslog | 适合Qt/C++ 平台 |
Log4r | 适合Ruby |
JDK1.4's util.logging framework | 适合JDK1.4Util |
二.在Web应用系统中使用日志的步骤:
1. 下载相关的Jar文件:logging-log4j-1.2.13.zip解压得到log4j-1.2.14.jar文件
2. 部署Jar文件到项目中。将log4j-1.2.14.jar复制到项目文件夹\WEB-INF\lib文件夹下,并在项目的构建路径中导入该文件:右击工程名称-【属性】-【java构建路径】-【添加外部JAR(X)】-选择log4j-1.2.8.jar,
3. 在项目文件夹根目录下建立通用日志包的属性文件(Log4j.properties或common-logging.properties)中指定要使用的日志器(Log4j、SimpleLog、NoOpLog)。指定Log4j的属性文件Log4j.properties内容如下:
org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JcategoryLog
指定SimpleLog日志器的属性文件simpleLog.properties内容如下:
4. 为该日志器设定日志级、输出格式、地点等属性。
org.apache.commons.logging.simplelog.defaultlog=info
三.三个Log4j.properties内容设置实例:
#设置com.unmi域对应的日志级别INFO,DEBUG,WARN,ERROR和输出地A1,A2
#log4j.logger.com.unmi=ERROR,A1-->子节点com.unmi可以继承父节点rootLogger关于的A1的配置属性 |
程序如下
PropertyConfigurator.configure("D:/Javas/tomcat4/webapps/Eclipse/test.properties");//加载.properties文件
//Logger log=Logger.getLogger("chan.test");----------->chan.test节点没有特殊配置,只能继承rootLogger输出到console
Logger log = Logger.getLogger("com.unmi");
Logger log1 = Logger.getLogger("com.unmi.special");
log.info("测试");
log1.error("测试错误");
日志文件默认输出是项目根文件夹。我们可以定义一个文件夹专门来存放日志文件。
1.NETP04项目中Log4j.properties的设置内容:
log4j.rootCategory=ERROR, stdout, logfile
log4j.logger.neo=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender # 输出到控制台的设置
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # 以指定的布局模式存储
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
# 指定输出到控制台的格式,具体效果如下:
#2006-11-21 12:49:34,984 INFO [neo.core.bean.BeanManager] - <BeanManager init finished.>
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender # 每天产生一个文件
log4j.appender.logfile.File=${netp.root}/WEB-INF/logs/netp.log # 日志文件的位置
log4j.appender.logfile.DatePattern=.yyyy-MM-dd
# 当天备份文件名为netp.log,过去的记录在名称为 netp.log.yyyy-mm-dd的文件中。
# log4j.appender.R.DatePattern = .yyyy-MM 每月产生一个文件
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
# 指定输出到日志文件的格式:date priority [category]-<message>line_separator
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - <%m>%n
2.另一个Log4j.properties的设置内容:
log4j.rootCategory=INFO, stdout, logfile
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=springapp.log
log4j.appender.logfile.MaxFileSize=512KB
# Keep three backup files
log4j.appender.logfile.MaxBackupIndex=3
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
#Pattern to output : date priority [category] - <message>line_separator
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - <%m>%n
四.Log4j配置文件:
Log4j由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地,日志信息的输出格式。日志信息的优先级从高到低有ERROR、WARN、INFO、DEBUG,分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将打印到控制台还是文件中;而输出格式则控制了日志信息的显示内容。Log4j支持两种配置文件格式,一种是XML格式的文件,一种是Java特性文件(键=值)。
1.配置根Logger,其语法为:
log4j.rootLogger = [ level ] , appenderName, appenderName, …
其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的级别。Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。 appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。
2.配置日志信息输出目的地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(文件大小到达指定尺寸的时候产生一个新的文件),
org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
3.配置日志信息的格式(布局),其语法为:
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.HTMLLayout(以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月18日 22:10:28,921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)
五.在Java类文件里使用Log4j:
1.Import需要的包文件:import org.apache.log4j.*;
2.定义Logger对象
static Logger logger = Logger.getLogger(Frame1.class.getName());在程序申明变量的地方定义这个对象,并且是静态对象。其中的Frame1是你当前类的名称。
3.装载属性文件:
PropertyConfigurator.configure("Log4j.properties");
Log4j会在与Log4j.properties同目录的地方创建example.log文件,并记录日志信息,当文件的尺寸大于100KB时,log4J会创建一个新的example.log文件,同时备份example.log文件。备份的文件个数取决于MaxBackupIndex属性。
六.Log4j在Eclipse上的应用过程
package com.log4j; import org.apache.log4j.*; public class MyLogTest { static Logger logger = Logger.getLogger(MyLogTest.class.getName()); public static void main(String[] args) { PropertyConfigurator.configure("Log4j.properties"); MyLogTest.logger.info("测试信息开始"); MyLogTest.logger.info("测试信息结束"); } } |
输出结果:
INFO [main] (MyLogTest.java:16) - 测试信息开始 INFO [main] (MyLogTest.java:17) - 测试信息结束 |
七.在代码中使用Log4j
1.得到记录器
使用Log4j,第一步就是获取日志记录器,这个记录器将负责控制日志信息。其语法为:
public static Logger getLogger( String name)
通过指定的名字获得记录器,如果必要的话,则为这个名字创建一个新的记录器。Name一般取本类的名字,比如:
static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () )
2.读取配置文件
当获得了日志记录器之后,第二步将配置Log4j环境,其语法为:
BasicConfigurator.configure ():自动快速地使用缺省Log4j环境。
PropertyConfigurator.configure ( String configFilename) :读取使用Java的特性文件编写的配置文件。
DOMConfigurator.configure ( String filename ) :读取XML形式的配置文件。
3.插入记录信息(格式化日志信息)
当上两个必要步骤执行完毕,您就可以轻松地使用不同优先级别的日志记录语句插入到您想记录日志的任何地方,其语法如下:
Logger.debug ( Object message ) ;
Logger.info ( Object message ) ;
Logger.warn ( Object message ) ;
Logger.error ( Object message ) ;
在NETP项目中,在web.xml有几个条目和log4j有关,它们是:
- 1.
- <context-param>
- <param-name>webAppRootKey</param-name>
- <param-value>petclinic.root</param-value>
- </context-param>
- 2.
- <context-param>
- <param-name>log4jConfigLocation</param-name>
- <param-value>/WEB-INFclasseslog4j.properties</param-value>
- </context-param>
- 3.(该条目在petclinic中被注释掉了)
- <listener>
- <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
- </listener>
我们知道,在web-application中使用log4j,有很多配置方式:
a.用servlet或者ServletContextListener对log4j做配置。通常,你不需要亲自编写servlet或者listener,比如直接利用log4j的com.apache.jakarta.log4j.Log4jInit类,Spring的org.springframework.web.util.Log4jConfigServlet和org.springframework.web.util.ServletContextListener ,这种方式配置灵活,可以通过参数条目自行指定log4j.properties的位置。
b.把log4j的默认配置文件(log4j.properties)放在classpath中,通常是/web-inf/classes目录下.这种方式是log4j的默认配置方式,无须其他配置。缺点就是无法灵活的通过配置文件来指定log4j.properties的文件位置。在我们的petclinic项目中,因为listener条目被注释,所以采用的也是这种缺省方式。
现在我们考虑listener条目没有被注释的情况,这种情况和注册Log4jConfigServlet的目的是一样的,只是必须在支持listener的servlet container中使用。
找到.Log4jConfigServlet和ServletContextListener的源码,他们都在适当的地方(callback method)调用了Log4jWebConfigurer.initLogging(getServletContext());定位到这个方法,第一句就是:WebUtils.setWebAppRootSystemProperty(servletContext);再定位到该方法,方法很短:
- public static void setWebAppRootSystemProperty(ServletContext servletContext) throws java/lang/IllegalStateException.java.html" target="_blank">IllegalStateException {
- java/lang/String.java.html" target="_blank">String param = servletContext.getInitParameter(WEB_APP_ROOT_KEY_PARAM);
- java/lang/String.java.html" target="_blank">String key = (param != null ? param : DEFAULT_WEB_APP_ROOT_KEY);
- java/lang/String.java.html" target="_blank">String oldValue = java/lang/System.java.html" target="_blank">System.getProperty(key);
- if (oldValue != null) {
- throw new java/lang/IllegalStateException.java.html" target="_blank">IllegalStateException("WARNING: Web app root system property already set: " + key + " = " +
- oldValue + " - Choose unique webAppRootKey values in your web.xml files!");
- }
- java/lang/String.java.html" target="_blank">String root = servletContext.getRealPath("/");
- if (root == null) {
- throw new java/lang/IllegalStateException.java.html" target="_blank">IllegalStateException("Cannot set web app root system property when WAR file is not
- expanded");
- }
- java/lang/System.java.html" target="_blank">System.setProperty(key, root);
- servletContext.log("Set web app root system property: " + key + " = " + root);
- }
从代码看出,该方法其实就是把该web application的根目录的绝对文件路径作为属性保存在System的属性列表中。该属性的名字,由web.xml文件中的名为"webAppRootKey"的参数值指出。如果不在web.xml中定义webAppRootKey参数,那么属性名就是缺省的"webapp.root".在我们的petclinic项目中已经定义了webAppRootKey参数,其值为"petclinic.root",因此,属性的名字就是"petclinic.root".
再回到Log4jWebConfigurer.initLogging(getServletContext()),接下来的行为是从web.xml中获取log4jConfigLocation和log4jRefreshInterval.前者指出log4j配置文件(有可能是xml格式)的位置和名字,后者则指出重新都取配置文件的时间间隔.然后调用Log4jConfigurer.initLogging()方法对log4j做配置。从Log4jConfigurer.initLogging()方法我们可以看到,针对不同格式的配置文件(properties或者xml),Log4jConfigurer采用不同的lo4j configurator类做配置,例如DOMConfigurator或者PropertyConfigurator。
至此,关于petclinic中关于log4j的配置,我们已经基本上弄清楚了。可是System对象中的petclinic.root属性在什么时候使用呢?在web-inf/classes下面的log4j.properties文件中,有这么一句:
log4j.appender.logfile.File=${petclinic.root}/WEB-INF/petclinic.log
这样,我们就用上了petclinic.root属性了。从上面的分析可知,如果你不在web.xml中定义webAppRootKey参数,那么你就得把log4j.appender.logfile.File =${petclinic.root}/WEB-INF/petclinic.log中的petclinic.root变量改为webapp.root变量或者干脆换成别的绝对路径了。