Log4j 使用方法


Log4j 基本使用方法 Log4j 由三个重要的组件构成:日志信息的优先级,日志信息的输出目的地, 日志信息的输出格式。日志信息的优先级从高到低有 ERROR、WARN、INFO、DEBUG, 分别用来指定这条日志信息的重要程度;日志信息的输出目的地指定了日志将打 印到控制台还是文件中;而输出格式则控制了日志信息的显示内容。 一、定义配置文件 其实您也可以完全不使用配置文件,而是在代码中配置 Log4j 环境。但是, 使用配置文件将使您的应用程序更加灵活。Log4j 支持两种配置文件格式,一种 是 XML 格式的文件,一种是 Java 特性文件(键=值)。下面我们介绍使用 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) 二、在代码中使用 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 ) ; log4j 使用示例 log4j 使用示例 --by blues(zhaochaohua@sina.com) PART 1 介绍 log4j 的好处在于: 1.通过修改配置文件,就可以决定 log 信息输出到何处(console,文件,...),是否输出。 这样,在系统开发阶段可以打印详细的 log 信息以跟踪系统运行情况,而在系统稳定后可以关闭 log 输出,从而在能跟 踪系统运行情况的同时,又减少了垃圾代码(System.out.println(...)等)。 2.使用 log4j,需要整个系统有一个统一的 log 机制,有利于系统的规划。 log4j 的使用本身很简单。但合理地规划一个系统的统一 log 机制需要周全的考虑。 其他关于 log4j 的信息参看 log4j 自带的文档。 PART II 配置文件详细解释 先看一个配置文件的例子: 1.配置文件的例子 log4j.rootLogger=DEBUG #将 DAO 层 log 记录到 DAOLog,allLog 中 log4j.logger.DAO=DEBUG,A2,A4 #将逻辑层 log 记录到 BusinessLog,allLog 中 log4j.logger.Businesslog=DEBUG,A3,A4 #A1--打印到屏幕上 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=%-5p [%t] %37c %3x - %m%n #A2--打印到文件 DAOLog 中--专门为 DAO 层服务 log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender log4j.appender.A2.file=DAOLog log4j.appender.A2.DatePattern='.'yyyy-MM-ddlog4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n #A3--打印到文件 BusinessLog 中--专门记录逻辑处理层服务 log 信息 log4j.appender.A3=org.apache.log4j.DailyRollingFileAppender log4j.appender.A3.file=BusinessLoglog4j.appender.A3.DatePattern='.'yyyy-MM-dd log4j.appender.A3.layout=org.apache.log4j.PatternLayout log4j.appender.A3.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n #A4--打印到文件 alllog 中--记录所有 log 信息 log4j.appender.A4=org.apache.log4j.DailyRollingFileAppender log4j.appender.A4.file=alllog log4j.appender.A4.DatePattern='.'yyyy-MM-dd log4j.appender.A4.layout=org.apache.log4j.PatternLayout log4j.appender.A4.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n 2.Appender 的使用 一个 Appender 代表 log 信息要写向的一个地方。log4j 可使用的 Appender 有很多类型,这里只考虑 3 种: ConsoleAppender,FileAppender,DailyRollFileAppender 2.1 ConsoleAppender 如果使用 ConsoleAppender,那么 log 信息将写到 Console。就是直接把信息打印到 System.out 上了。 2.2 FileAppender 使用 FileAppender,那么 log 信息将写到指定的文件中。这应该是比较经常使用到的情况。 相应地,在配置文件中应该指定 log 输出的文件名。如下配置指定了 log 文件名为 demo.txt log4j.appender.A2.File=demo.txt 注意将 A2 替换为具体配置中 Appender 的别名。 2.3 DailyRollingAppender 使用 FileAppender 可以将 log 信息输出到文件中,但是如果文件太大了读起来就不方便了。这时就可以使用 DailyR ollingAppender。DailyRollingAppender 可以把 Log 信息输出到按照日期来区分的文件中。如下配置文件就会每天产 生一个 log 文件,每个 log 文件只记录当天的 log 信息: log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender log4j.appender.A2.file=demo log4j.appender.A2.DatePattern='.'yyyy-MM-dd log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%m%n 3.Layout 的配置 Layout 指定了 log 信息输出的样式。 详细信息请查看 PatternLayout 的 javadoc。 例子 1:显示日期和 log 信息 log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %m%n 打印的信息是: 2002-11-12 11:49:42,866 SELECT * FROM Role WHERE 1=1 order by createDate desc 例子 2:显示日期,log 发生地方和 log 信息 log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %l "#" %m%n2002-11-12 11:5 1:46,313 cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.java:409) "#" SELECT * FROM Role WHE RE 1=1 order by createDate desc 例子3:显示 log 级别,时间,调用方法,log 信息 log4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=[%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%nlog 信息:[DEBUG] 2002-11-12 12:00:57,376 method:cn.net.unet.weboa.system.dao.RoleDAO.select(RoleDAO.jav a:409)SELECT * FROM Role WHERE 1=1 order by createDate desc PART 3 log4j 的使用 log4j 使用步骤有 3 个: 3.1.根据配置文件初始化 log4j 配置文件如 PART 2所叙述。现在讲的是如何在程序中配置 log4j。 log4j 可以使用 3 中配置器来初始化:BasicConfigurator ,DOMConfigurator ,PropertyConfigurator 这里用的是 PropertyConfigurator。使用 PropertyConfigurator 适用于所有的系统。 如下的语句 PropertyConfigurator.configure("log4j.properties"); 就以 log4j.properties 为配置文件初始化好了 log4j 环境。 注意一点:这个语句只需要在系统启动的时候执行一次。例如:在 unet webOA 项目中可以这么用: 在 ActionServlet 的 init()方法中调用一次。 public class ActionServlet extends HttpServlet{ ... /*** Initialize global variables*/ public void init() throws ServletException { // 初始化 Action 资源 try{initLog4j(); ...}catch(IOException e){ throw new ServletException("Load ActionRes is Error"); } } ... protected void initLog4j(){ PropertyConfigurator.configure("log4j.properties"); } ... } //end class ActionServlet 3.2 在需要使用 log4j 的地方获取 Logger 实例 如下是 RoleDAO 类中的使用例子: static Logger log = Logger.getLogger("DAO"); 注意这里使用"DAO"标识符,那么对应的在配置文件中对应的配置信息如下: #定义 DAO Logger log4j.logger.DAO=DEBUG,A2 #设置 Appender A2 的属性 log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender log4j.appender.A2.file=demo log4j.appender.A2.DatePattern='.'yyyy-MM-ddlog4j.appender.A2.layout=org.apache.log4j.PatternLayout log4j.appender.A2.layout.ConversionPattern=%-5p %d{yyyy-MM-dd HH:mm:ss} %l%n%m%n public class RoleDAO extends BaseDBObject{ ... static Logger log = Logger.getLogger("DAO"); ... public BeanCollection selectAll() throws SQLException{ StringBuffer sql = new StringBuffer(SQLBUF_LEN); sql.append("SELECT * FROM " + tableName + " order by roldId"); //System.out.println(sql.toString()); log.debug(sql); ... } ... } 3.3 使用 Logger 对象的 debug,info,fatal...方法 log.debug("it is the debug info"); 附件 1:log4j 的一个 bug 当这样使用时,DailyRollingFileAppender 不能正确使用: public Class RoleDAO(){static Logger log = Logger.getLogger("DAO");//在每一次 new RoleDAO 对象的时候都 执行一次 configure()操作 public RoleDAO(TransactionManager transMgr) throws SQLException{...PropertyConf igurator.configure("log4j.properties");...}public void select(){...//使用 log4j 进行 log 记录 log.debug("...");...}}怎么解 决: 在系统启动时执行一次 PropertyConfigurator.configure("log4j.properties"); 之后就不再执行。 log4j 使用进阶 二 动态配置 log4j 1 配置外部配置文件来配置的基本步骤 1.1 一个运用配置文件的实例 Log4j 之所以能成功的原因之一是它的灵活性。但如果只是简单的调用 BasicConfigura tor.configure()来进行配置工作,那么所有的配置都是在函数中写死的,以后修改配 置就要修改原代码,这就不能体现出 log4j 的灵活性了,所以基本上不会通过 BasicCo nfigurator.configure()来进行配置工作的。 为了增加软件的灵活性,最常用的做法就是使用配置文件,如 web.xml 之于 J2EE,str uts-config.xml 之于 struts 一样,log4j 也提供了让我们把配置信息从程序转移到配 置文件中的方法。Log4j 提供了两种方式的配置文件:XML 文件和 Java 的 property 配 置文件。通过把配置信息转移到外部文件中,当我们要修改配置信息时,就可以直接修 改配置文件而不用去修改代码了,下面,我们就来完成一个通过配置文件来实现 log4j 的实例。 例 2-a: package TestLog4j; import org.apache.log4j.Logger; import org.apache.log4j.BasicConfigurator; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.Priority; public class TestLog4j { static Logger logger = Logger.getLogger(TestLog4j.class.getName()); public TestLog4j(){} public static void main(String[] args) { //通过 BasicConfigurator 类来初始化 //BasicConfigurator.configure(); //(1)通过配置文件来初始化 PropertyConfigurator.configure("F:\\nepalon\\log4j.properties"); logger.debug("Start of the main() in TestLog4j"); //代码(2) logger.info("Just testing a log message with priority set to INFO"); logger.warn("Just testing a log message with priority set to WARN"); logger.error("Just testing a log message with priority set to ERROR"); logger.fatal("Just testing a log message with priority set to FATAL"); logger.log(Priority.WARN, "Testing a log message use a alternate form"); logger.debug(TestLog4j.class.getName()); //代码(2) } } 在这个例子中,我们用 PropertyConfigurator.configure("F:\\nepalon\\log4j.prop erties")代替 BasicConfigurator.configure()进行配置。PropertyConfigurator.con figure()函数的参数可以是一个 properties 文件所在路径的 String 对象,可以是一个 properties 文件所在路径的 URL 对象,也可以是一个 properties 对象。通过 Property Configurator.configure()可以通过指定的 properties 文件来配置信息。如果要用 XM L 文件进行信息配置,可以在代码中调用 DOMConfigurator()函数来进行配置工作。在 这里,我们只以 properties 文件来完成例子。接着,我们来看一下 log4j.properties 文件中都有些什么东西: 例 2-b: 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 运行这个实例,运行结果为 0 [main] DEBUG TestLog4j.TestLog4j - Start of the main() in TestLog4j 20 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priori ty set to INFO 20 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priori ty set to WARN 20 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with prior ity set to ERROR 20 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with prior ity set to FATAL 180 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form 180 [main] DEBUG TestLog4j.TestLog4j - TestLog4j.TestLog4j 下面,我们分析一下这个配置文件。 1) 由于每一个 Logger 对旬都有一个级别,文件的第一行就是定义了一个 Logger 及其 级别。在这里定义了一个根记录器(root logger),这涉及到记录器的层次问题,在 些暂时不深入讨论,在后面的章节再进行讨论。 2) 第二行定义了一个名为 A1 的输出流,这个流就是控制台,所以通过 Logger 对象打 印的信息会在控制台输出。 3) 第三行定义了打印信息的布局。在这里我们用 PatternLayout 作为此记录器的布局, PatternLayout 允许你以灵活的格式来打印信息。 4) 第四行指定的打印信息的具体格式,从结果可知,这个实例的打印格式为:当前打 印语句所使用的时间 [日志所在的线程] 打印的级别 当前日志所在的类的全名 日志 信息。 现在我们来修改一下这个记录器的级别,把第一行的 DEBUG 改为 INFO,再运行程序,结 果将变为: 0 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priorit y set to INFO 10 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priori ty set to WARN 10 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with prior ity set to ERROR 10 [main] FATAL TestLog4j.TestLog4j - Just testing a log message with prior ity set to FATAL 10 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form 由于这个 Logger 的级别变为 INFO,而代码(2)是调用 debug()函数来输出日志信息时 只能当记录器级别为 DEBUG 时才输出信息,所以代码(2)将不输出信息。 1.2 实例原理 1.2.1 初始化配置信息 如果要通过 JAVA 的 properties 文件来配置信息,那么在代码中就要通过 PropertyCon figurator.configure()函数从 properties 文件中加载配置信息,这个函数有三种参数 形式:一个 properties 文件所在路径的 String 对象,可以是一个 properties 文件所 在路径的 URL 对象,也可以是一个 properties 对象。如果要用 XML 文件来配置信息, 则可用类型的 DOMConfigurator()函数来从一个 XML 文件中加载配置信息。 1.2.2 输出端 Appender 在上面的例子中,我们都是简单的把日志信息输出到控制台中。其实在 log4j 中还可以 把日志信息输出到其它的输出端,对于同一个日志信息,我们还可以让它同时输出到多 个输出端中,如同时在控制台和文件中进行打印。一个输出端就是一个 appender。要在 配置文件中定义一个 appender 有三步: 1) 在定义一个记录器的同时定义出该记录器的输出端 appender。在例 2 的配置文件的 第一句 log4j.rootLogger = DEBUG, A1 中,我们定义了一个根记录器,它的级别为 DE BUG,它有一个 appender 名为 A1。定义根记录器的格式为 log4j.rootLogger = [ leve l ], appendName1, appendName2, …appendNameN。同一个记录器可有多个输出端。 2) 定义 appender 的输出目的地。定义一个 appender 的输出目的地的格式为 log4j.ap pender.appenderName = fully.qualified.name.of.appender.class。log4j 提供了以 下几种常用的输出目的地: org.apache.log4j.ConsoleAppender,将日志信息输出到控制台 org.apache.log4j.Fi leAppender,将日志信息输出到一个文件 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 把日志信息输出到数据库中。 在例 2 中,log4j.appender.A1 = org.apache.log4j.ConsoleAppender 定义了名为 A1 的 appender 的输出目的地为控制台,所以日志信息将输出到控制台。 3) 定义与所选的输出目的地相关的参数,定义格式为: log4j.appender.appenderName.optionName1 = value1 …… log4j.appender.appenderName.optionNameN = valueN 其中一个最常用的参数 layout 将在下面介绍。 1.2.3 输出格式(布局)layout 通过 appender 可以控制输出的目的地,而 如果要控制输出的格式,就可通过 log4j 的 l ayout 组件来实现。通过配置文件定义一个 appender 的输出格式,也 通常需要两个步骤: 1) 定义 appender 的布局模式。定义一个 appender 的布局模式的格式为 log4j.append er.appenderName.layout = fully.qualified.name.of.layout.class。Log4j 提供的布 局模式有以下几种: ? org.apache.log4j.HTMLLayout,以 HTML 表格形式布局 ? org.apache.log4j.PatternLayout,可以灵活地指定布局模式 ? org.apache.log4j.SimpleLayout,包含日志信息的级别和信息字符串 在例 2 中 log4j.appender.A1.layout = org.apache.log4j.PatternLayout 定义了名 为 A1 的 appender 的布局模式为 PatternLayout。 2) 定义与所选的布局模式相关的设置信息,定义格式为: log4j.appender.appenderName.layout.optionName1 = value1 …… log4j.appender.appenderName.layout.optionNameN = valueN 选择了不同的布局模式可能会有不同的设置信息。实例 2 所选的布局模式 PatternLayo ut 的一个 PatternLayout 为 ConversionPattern ,通过定义这个 PatternLayout 的值, 我们可以指定输出信息的输出格式。在例 2 的配置文件中的定义如下 log4j.appender. A1.layout.ConversionPattern = %-4r [%t] %-5p %c %x - %m%n。在下面,我们将介 绍布局模式 PatternLayout 的参数 ConversionPattern 的各个值代表的含义。 1.2.4 ConversionPattern 参数的格式含义 格式名 含义 %c 输出日志信息所属的类的全名 %d 输出日志时间点的日期或时间,默认格式为 ISO8601,也可以在其后指定格式,比如:% d{yyy-MM-dd HH:mm:ss },输出类似:2002-10-18- 22:10:28 %f 输出日志信息所属的类的类名 %l 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行 %m 输出代码中指定的信息,如 log(message)中的 message %n 输出一个回车换行符,Windows 平台为“\r\n”,Unix 平台为“\n” %p 输出优先级,即 DEBUG,INFO,WARN,ERROR,FATAL。如果是调用 debug()输出的, 则为 DEBUG,依此类推 %r 输出自应用启动到输出该日志信息所耗费的毫秒数 %t 输出产生该日志事件的线程名 1.3 定义多个输出目的地的实例 从上面的实例原理中我们已经知道,同一个日志信息可以同时输出到多个输出目的地, 在这个例子中,我们将实现一个把日志信息同时输出到控制器、一个文件中的实例和数 据库中。这个实例的 Java 代码我们沿用例 2 中的代码,我们只需修改配置文件即可。 这也体现了 log4j 的灵活性。 例 3-a: create table log4j( logID int primary key identity, message varchar(1024), priority varchar(10), milliseconds int, category varchar(256), thread varchar(100), NDC varchar(256), createDate datetime, location varchar(256), caller varchar(100), method varchar(100), filename varchar(100), line int ) 例 3-b: #1 定义了两个输出端 log4j.rootLogger = INFO, A1, A2,A3 #2 定义 A1 输出到控制器 log4j.appender.A1 = org.apache.log4j.ConsoleAppender #3 定义 A1 的布局模式为 PatternLayout log4j.appender.A1.layout = org.apache.log4j.PatternLayout #4 定义 A1 的输出格式 log4j.appender.A1.layout.ConversionPattern = %-4r [%t] %-5p %c - %m%n #5 定义 A2 输出到文件 log4j.appender.A2 = org.apache.log4j.RollingFileAppender #6 定义 A2 要输出到哪一个文件 log4j.appender.A2.File = F:\\nepalon\\classes\\example3.log #7 定义 A2 的输出文件的最大长度 log4j.appender.A2.MaxFileSize = 1KB #8 定义 A2 的备份文件数 log4j.appender.A2.MaxBackupIndex = 3 #9 定义 A2 的布局模式为 PatternLayout log4j.appender.A2.layout = org.apache.log4j.PatternLayout #10 定义 A2 的输出格式 log4j.appender.A2.layout.ConversionPattern = %d{yyyy-MM-dd hh:mm:ss}:%p %t %c - %m%n #11 区 定义 A3 输出到数据库 log4j.appender.A3 = org.apache.log4j.jdbc.JDBCAppender log4j.appender.A3.BufferSize = 40 log4j.appender.A3.Driver = com.microsoft.jdbc.sqlserver.SQLServerDriver log4j.appender.A3.URL = jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseN ame=nepalon log4j.appender.A3.User = sa log4j.appender.A3.Password = log4j.appender.A3.layout = org.apache.log4j.PatternLayout log4j.appender.A3.layout.ConversionPattern = INSERT INTO log4j (createDate, thread, priority, category, message) values(getdate(), '%t', '%-5p', '%c', '%m') 配置文件中的 6、7、8 行显示了输出端为 RollingFileAppender 的特有参数及其运用的 方法。11 区显示了输出端为 JDBCAppender 的特有参数及其运用方法。在这着重讲解一 下 6、7、8 行的作用。6 行指定日志信息输出到哪个文件,7 行指定日志文件的最大长 度,最后要详细介绍 8 行。第 8 行的参数是设置备份文件的个数的参数,在这里我们设 置为 3,表示最多有 3 个备份文件,具体作用为: 1) 当 example3.log 文件的大小超过 K 时,就把文件改名为 example3.log.1,同时生成 一个新的 example3.log 文件 2) 当 example3.log 文件的大小再次超过 1K,又把文件改名为 example3.log.1。但由 于此时 example3.log.1 已存在,则先把 example3.log.1 更名为 example3.log.2,再把 example3.log 文件改名为 example3.log.1 3) 同理,当 example3.log 文件的大小再次超过 1K,先把 example3.log.2 文件更名为 example3.log.3,把 example3.log.1 文件更名为 example3.log.2,再把 example3.log 文件改名为 example3.log.1 4) 当 example3.log 文件的大小再次超过 1K,先把 example3.log.2 文件更名为 exampl e3.log.3,旧的 example3.log.3 文件将被覆盖;把 example3.log.1 文件更名为 examp le3.log.2,旧的 example3.log.2 文件被覆盖;最后把 example3.log 文件改名为 exam ple3.log.1 并覆盖掉旧的 example3.log.1 文件。 运行结果将分为两部分 在控制器中: 0 [main] INFO TestLog4j.TestLog4j - Just testing a log message with priorit y set to INFO 11 [main] WARN TestLog4j.TestLog4j - Just testing a log message with priori ty set to WARN 21 [main] ERROR TestLog4j.TestLog4j - Just testing a log message with prior ity set to ERROR 21 [main] FATAL TestLog4j.TestLog4j - Just testing a log m essage with priority set to FATAL 21 [main] WARN TestLog4j.TestLog4j - Testing a log message use a alternate form 在文件 example3.log 中: 2003-12-18 04:23:02:INFO main TestLog4j.TestLog4j - Just testing a log mess age with priority set to INFO 2003-12-18 04:23:02:WARN main TestLog4j.TestLog4j - Just testing a log mess age with priority set to WARN 2003-12-18 04:23:02:ERROR main TestLog4j.TestLog4j - Just testing a log mes sage with priority set to ERROR 2003-12-18 04:23:02:FATAL main TestLog4j.TestLog4j - Just testing a log mes sage with priority set to FATAL 2003-12-18 04:23:02:WARN main TestLog4j.TestLog4j - Testing a log message u se a alternate form 1.4 配置 log4j 的总结 这个教程到这里,关于配置 log4j 的配置文件的基本原理已经讲完了,而且通过例 3 我 们已经可以完成基本的日志工作了。现在,我们就做一个总结。配置一个配置文件的基 本步骤如下: 1) 定义一个 Logger。在定义 Logger 时指定该 Logger 的级别级其输出目的地。定义 Lo gger 的格式为 log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN。 2) 定义 appender 的输出目的地。定义一个 appender 的输出目的地的格式为 log4j.appender.appenderName = fully.qualified.name.of.appender.class。 log4j 提供的输出端有 ConsoleAppender、FileAppender 、DailyRollingFileAppender、 RollingFileAppender 和 WriterAppender。 3) 定义 appender 的除布局模式外的其它相关参数,如例 3 中第 6、7、8 定义了 A2 的 相关参数。定义格式为 log4j.appender.appenderName.optionName1 = value1 …… log4j.appender.appenderName.optionNameN = valueN 如果除了布局模式外不需要定义别的参数,可跳过这一步(如例 3 中的 A1)。 4) 定义 appender 的布局模式。定义一个 appender 的布局模式的格式为 log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class。 布局模式其实也是步骤 3)中的一个部分,只是布局模式参数是每一个 appender 必须定 义的参数。Log4j 提供的布局模式有 HTMLLayout、PatternLayout 和 SimpleLayout。 5) 定义与所选的布局模式相关的设置信息,定义格式为 log4j.appender.appenderName.layout.optionName1 = value1 …… log4j.appender.appenderName.layout.optionNameN = valueN 2 记录器的层次 Logger hierarchy 2.1 何为记录器的层次 hierarchy 首先,我们先看一下何为层次,以我们最熟悉的继承为例,下面是一张类图 在这个继承体系中,类 B 是类 C 的父类,类 A 是类 C 的祖先类,类 D 是类 C 的子类。这 些类之间就构成一种层次关系。在这些具有层次关系的类中,子类都可继承它的父类的 特征,如类 B 的对象能调用类 A 中的非 private 实例变量和函数;而类 C 由于继承自类 B,所以类 B 的对象可以同时调用类 A 和类 B 中的非 private 实例变量和函数。 在 log4j 中,处于不同层次中的 Logger 也具有象类这样的继承关系。 2.2 记录器的层次 如果一个应用中包含了上千个类,那么也几乎需要上千个 Logger 实例。如何对这上千 个 Logger 实例进行方便地配置,就是一个很重要的问题。Log4J 采用了一种树状的继承 层次巧妙地解决了这个问题。在 Log4J 中 Logger 是具有层次关系的。它有一个共同的 根,位于最上层,其它 Logger 遵循类似包的层次。下面我们将进行介绍。 2.2.1 根记录器 root logger 就象一个 Java 中的 Object 类一样,log4j 中的 logger 层次中有一个称之为根记录器的 记录器,其它所有的记录器都继承自这个根记录器。根记录器有两个特征: 1) 根记录器总是存在。就像 Java 中的 Object 类一样,因为用 log4j 输出日志信息是 通过记录器来实现的,所以只要你应用了 log4j,根记录器就肯定存在的。 2) 根记录器没有名称,所以不能通过名称来取得根记录器。但在 Logger 类中提供了 g etRootLogger()的方法来取得根记录器。 2.2.2 记录器的层次 Logger 遵循类似包的层次。如 static Logger rootLog = Logger.getRootLogger(); static Logger log1 = Logger.getLogger("test4j"); static Logger log2 = Logger.getLogger("test4j.test4j2"); static Logger log3 = Logger.getLogger("test4j.test4j2.test4j2"); 那么 rootLog 是 log2 的祖先子记录器,log1 是 log2 的父子记录器,log3 是 log2 的子 记录器。记录器象 Java 中的类继承一样,子记录器可以继承父记录器的设置信息,也 可以可以覆写相应的信息。 首先先看一下记录器层次中的继承有什么用处。假设程序中的每个包都具有一些基本的 日志信息,而包中的不同包可能会有些额外的日志信息要输出,这种情况就可以象处理 Java 中的类一样,运用 Logger 中的层次关系来达到目的。假设有个名为 A 的包,我包 下的所有类都要把日志信息输出到控制台中;A.B 包除了输出到控制台外还要输出到文 件中;A.C 包除了输出到控制台中还要输出到 HTML 文档中。这样我们就可以通过定义一 个父记录器 A,它负责把日志信息输出到控制台中;定义一个 A 的子记录器 A.B,它负 责把日志信息输出到文件中;定义一个 A 的子记录器 A.C,它负责把日志信息输出到 HT ML 文档中。 记录器遵循的是类似包的层次,这样做为我们带来了大大的方便。Logger 类中的 getLo gger()方法可以取得 Logger 对象,这个方法有三种参数形式 String、Class 和 URL,其 实不论是用哪一种,最终都是通过记录器的名字来取得记录器对象的。如果要取得一个 名为 A.B 的记录器对象,我们可以 Logger.getLogger(“A.B”)。但从上面的例子中, 我们都是通过 Logger.getLogger(TestLog4j.class.getName())这种方法来取得记录器 对象。这是为什么呢?现在我们假设 A.B 的包下有一个类 BClass,那么我们调用 BClas s.class.getName()得到的是这个类的全名 A.B.BClass。所以当调用 Logger.getLogger (BClass.class.getName())时,最理想的情况是返回名为 A.B.BClass 的记录器对象。 但是如果不存在名为 A.B.BClass 的记录器时它会怎样呢?其实通过 Logger 类的 getLo gger 方法取得记录器时存在下面两种情况: 1) 如果存在与所要找的名字完全相同的记录器,则返回相应的记录器对象。 当调用 Logger.getLogger(BClass.class.getName())时,如果定义了名为 A.B.BClass 的记录器,它就返回该记录器的对象。 2) 但如果找不到,它会尝试返回在记录器层次中与所要找的记录器最接近的记录器对 象。 当调用 Logger.getLogger(BClass.class.getName())时,如果没有定义了名为 A.B.C.C lass 的记录器,那会尝试返回名为 A.B 的记录器的对象;如果又没有定义名为 A.B 的记 录器,它会尝试返回名为 A 的记录器的对象;如果也没定义名为 A 的记录器,它就会返 回根记录器的对象,而根记录器是必须存在的,所以你总能得到一个记录器对象。 好了,现在我们回到前面的问题,我们为什么总要通过 Logger.getLogger(BClass.cla ss.getName())这种以类全名作为参数来取得记录器对象呢?其实这是为了管理方便。 因为我们在定义设计 Logger 时也遵循类似包的规则,使设计器的名称与程序中的类包 对应。如上面的假设中我们的程序中有 A 包,A 包下有 B 包和 C 包,B 包下又有类 BCla ss,那么我们就可使设计器的名为 A、A.B、A.C、A.B.BClass,以此类推。那么当我们 通过类命名来取得设计器对象时,总能取到与所要的设计器最接近的设计器对象。 2.3 如何应用记录器的层次 2.3.1 如果定义及获取不同层次的记录器 任何一个记录器的使用都有两个步骤: 1) 在配置文件中定义相应的记录器。 在配置文件中定义记录器的格式有两种 定义根记录器的格式为 log4j.rootLogger = [ level ], appendName1, appendName2, …appendNameN 定义一个非根记录器的格式为 log4j.logger.loggerName1 = [ level ], appendName1,…appendNameN …… log4j.logger.loggerNameM = [ level ], appendName1, …appendNameN 我们可以定义任意个非根记录器。 2) 在代码中调用 Logger 类的取得记录器方法取得相应的记录器对象。 要取得根记录器对象可通过 Logger.getRootLogger()函数,要取得非根记录器可通过 L ogger.getLogger()函数。 理论知道就讲到这里,纸上得来终觉浅,下面,我们来小小演练一下。 例 4-a: package TestLog4j; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.Priority; import TestLog4j.TestLog4j2.TestLog4j2; public class TestLog4j { static Logger logger = Logger.getLogger(TestLog4j.class.getName()); //(2) public TestLog4j(){} public static void main(String[] args) { //同时输出到控制台和一个文件的实例并实现了 Logger 的继承 PropertyConfigurator.configure("F:\\nepalon\\log4j2.properties"); logger.debug("Start of the main() in TestLog4j"); logger.info("Just testing a log message with priority set to INFO"); logger.warn("Just testing a log message with priority set to WARN"); logger.error("Just testing a log message with priority set to ERROR"); logger.fatal("Just testing a log message with priority set to FATAL"); logger.log(Priority.WARN, "Testing a log message use a alternate form"); logger.debug(TestLog4j.class.getName()); TestLog4j2 testLog4j2 = new TestLog4j2(); //(1) testLog4j2.testLog(); } } 在类 TestLog4j 中我们调用了另一个类 TestLog4j2,下面看一下类 TestLog4j2 的代码。 例 4-b: package TestLog4j.TestLog4j2; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.Priority; public class TestLog4j2 { static Logger logger = Logger.getLogger(TestLog4j2.class.getName()); //(1) public TestLog4j2(){} public void testLog() { //同时输出到控制台和一个文件的实例 PropertyConfigurator.configure("F:\\nepalon\\log4j2.properties"); logger.debug("2Start of the main()"); logger.info("2Just testing a log message with priority set to INFO"); logger.warn("2Just testing a log message with priority set to WARN"); logger.error("2Just testing a log message with priority set to ERROR"); logger.fatal("2Just testing a log message with priority set to FATAL"); logger.log(Priority.DEBUG, "Testing a log message use a alternate form"); logger.debug("2End of the main()"); } } 最后我们来看一下配置文件。 例 4-c: log4j2.properties 文件内容 #1 区 #### Use two appenders, one to log to console, another to log to a file log4j.rootLogger = debug, stdout #2 区 #Print only messages of priority WARN or higher for your category log4j.logger.TestLog4j= , R log4j.logger.TestLog4j.TestLog4j2=WARN #3 区 #### First appender writes to console 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 #4 区 #### Second appender writes to a file log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=F:\\nepalon\\classes\\TestLog4j\\example.log # Control the maximum log file size log4j.appender.R.MaxFileSize=100KB # Archive log files (one backup file here) log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%d{yyyy-MM-dd hh:mm:ss}:%p %t %c - %m%n 先看一下运行结果。 在控制台中的结果为: DEBUG [main] (?:?) - Start of the main() in TestLog4j INFO [main] (?:?) - Just testing a log message with priority set to INFO WARN [main] (?:?) - Just testing a log message with priority set to WARN ERROR [main] (?:?) - Just testing a log message with priority set to ERROR FATAL [main] (?:?) - Just testing a log message with priority set to FATAL WARN [main] (?:?) - Testing a log message use a alternate form DEBUG [main] (?:?) - TestLog4j.TestLog4j WARN [main] (?:?) - 2Just testing a log message with priority set to WARN ERROR [main] (?:?) - 2Just testing a log message with priority set to ERROR FATAL [main] (?:?) - 2Just testing a log message with priority set to FATAL 输出文件的结果为: 2003-12-19 04:19:44:DEBUG main TestLog4j.TestLog4j - Start of the main() in TestLog4j 2003-12-19 04:19:44:INFO main TestLog4j.TestLog4j - Just testing a log mess age with priority set to INFO 2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j - Just testing a log mess age with priority set to WARN 2003-12-19 04:19:44:ERROR main TestLog4j.TestLog4j - Just testing a log mes sage with priority set to ERROR 2003-12-19 04:19:44:FATAL main TestLog4j.TestLog4j - Just testing a log mes sage with priority set to FATAL 2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j - Testing a log message u se a alternate form 2003-12-19 04:19:44:DEBUG main TestLog4j.TestLog4j - TestLog4j.TestLog4j 2003-12-19 04:19:44:WARN main TestLog4j.TestLog4j2.TestLog4j2 - 2Just testi ng a log message with priority set to WARN 2003-12-19 04:19:44:ERROR main TestLog4j.TestLog4j2.TestLog4j2 - 2Just test ing a log message with priority set to ERROR 2003-12-19 04:19:44:FATAL main TestLog4j.TestLog4j2.TestLog4j2 - 2Just test ing a log message with priority set to FATAL 首先,先来看一下配置文件都有些什么东西。 1) 在 1 区中定义了一个根记录器。这个根记录器具有 DEBUG 级别并有一个名称为 stdo ut 的输出端 appender。 2) 2 区中的内容是这一节的重点,也是应用到记录器层次的地方,但其实也只有两句, 充分体现了 log4j 的简单性。在这里,我们定义了两个名称分别为 TestLog4j 和 TestL og4j.TestLog4j2 设计器。 ? 在定义 TestLog4j 记录器时没有指定级别,所以它的级别继承自它的父记录器,即要 记录器,所以它的级别也为 DEBUG。在定义 TestLog4j 记录器时又定义了一个名称为 R 的输出端,所以它的输出端有两个,一个从根记录器继承而来的名为 stdout 的输出端, 另一个为在此定义的名为 R 的输出端。在此需要注意的是,在定义记录器时必须先定义 记录器的级别,然后才是记录器的输出端。如果只想定义输出端而不定义级别,则虽然 级别可以为空,但逗号分隔符不能省略。如定义 TestLog4j 记录器的做法。 ? 在定义 TestLog4j.TestLog4j2 记录器时又指定了它的级别,由于一个记录器的级别 只能有一个,所以新指定的级别将覆写掉它的父记录器的级别(这就象 Java 中的多态)。 我们没有定义 TestLog4j.TestLog4j2 记录器的输出端,所以它的输出端将从它的父记 录器中继承而来。它的父记录器为 estLog4j 记录器,所以它和 estLog4j 记录器一样具 有两个名称分别为 stdout 和 R 的输出端。 3) 剩下的 3 区和 4 区分别设置了两个输出端的参数值。 接下来,回到我们的代码,看一下是如何取得记录器,在取记录器时又发生了什么。 1) 例 4-a 中的代码(2)中,语句 Logger.getLogger()中的参数 TestLog4j.class.get Name()的值为 TestLog4j. TestLog4j,所以此语句的结果是取得一个名为 TestLog4j. TestLog4j 的记录器的对象。但在配置文件中并没有定义这样的记录器,所以最终将返 回与所需的名称 TestLog4j. TestLog4j 最接近的记录器对象,即名为 TestLog4j 的记 录器的对象。 2) 例 4-b 中的代码(1)的原理与例 4-a 中的代码(2)相似,期望取得的是名为 Test Log4j.TestLog4j2. TestLog4j2 的记录器对象,但最终返回的是 TestLog4j.TestLog4j 2 记录器的对象。 三 log4j 与 J2EE 的结合 到目前为止,这篇文章讲的都是如何在 application 中应用 log4j,而 Java 现在的应用 主流是 J2EE 和 J2ME。现在,我们来看一下要如何在 J2EE 开发中应用 log4j。其实在 W eb application 中应用 log4j 也很简单,与在 application 中应用 log4j 不同之处就是 要在所有应用 log4j 的代码之前对 log4j 进行初始化。所以,我们在 web application 中就要把 log4j 的初始化工作独立出来,把它放在 Servlet 中。下面,我们看一个例子。 例 5-a: 进行初始化的 Servlet: import org.apache.log4j.PropertyConfigurator; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * log4j.jar 的初始化类,参考 web.xml */ public class Log4jInit extends HttpServlet { public void init() { //通过 web.xml 来动态取得配置文件 String prefix = getServletContext().getRealPath("/"); String file = getInitParameter("log4j-init-file"); // 如果没有给出相应的配置文件,则不进行初始化 if(file != null) { PropertyConfigurator.configure(prefix+file); //(1) } } public void doGet(HttpServletRequest req, HttpServletResponse res) {} } 下面来看一下这个 Servlet 在 web.xml 中的定义。 例 5-b: log4j-init TestLog4j.Log4jInit log4j-init-file sort.properties 1 因为 log4j 的初始化要在所有的 log4j 调用之前完成,所以在 web.xml 文件中,我们一 定要把对应的 Servlet 定义的 load-on-startup 应设为 1,以便在 Web 容器启动时即装 入该 Servlet。 完成了这两个步骤这后,我们就可以象在 application 开发中一样在 web application 任何地方应用 log4j 了。下面是在 javabean 中的应用的一个例子。 例 5-c: import org.apache.log4j.Logger; public class InfoForm { static Logger logger = Logger.getLogger(InfoForm.class); protected String title; protected String content; public InfoForm() {} public void setTitle(Object value) { logger.debug("nepalon:title = " + title); title = value; } public String getTitle() { logger.debug("nepalon:title = " + title); return title; } public void setContent(String value) { content = value; logger.debug("nepalon: content() = " + content); } public String getContent() { logger.debug("nepalon: content = \n" + content); return content; } }
还剩19页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

502239585

贡献于2011-11-17

下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf