一:Log4j简单常识
1. 日志管理提供了如下的好处:1)记录程序运行时的出错信息,便于开发人员的分析和修正Debug。 2)充当集成开发环境中的调试器的作用。向文件活控制台打印代码的错误信息。 3)监视程序运行的情况,周期性的记录到文件中活数据库中,以便进行统计分析。
2. Log的显示分两种情况,一个是在一些小的项目中,通常使用System.out.println();来向控制台输出信息。第二个是在大型的项目中,通常需要开发以个日志组件,利用日志类在程序中输出日志信息。
二:Log4j介绍
我们在使用Log4j时,语言的范围是比较广的。可以在 C、C++、C#、Perl,Phthon和PL/SQL等程序中使用Log4j,
Log4j的组成:
Log4j由三种主要的组件组成,Logger、Appender和Layout.这三种类型的组件协同工作,使得开发人员可以依照消息的类型和级别来记录消息,并且在程序运行时控制这些消息以什么样的格式在什么地方输出。
Log4j的组件:
Logger组件(记录器)
记录器组件负责产生日志,并能够对日志信息进行分类筛选,控制什么样的日志应该被输出,什么样的日志应该被忽略。
Log4j允许程序员定义多个记录器,每个记录器都有自己的名字,记录器之间通过名字来表明隶属关系或者时家族关系。例如:记录器a.b 和a.b.c是父子关系,而a与a.b.c是祖先与后代的关系。通过这样的隶属关系,可以描述不同的记录器之间的逻辑关系。
在Log4j中,有一个根记录器(org.apche.log4j.Logger)类,位于记录器各层次的最顶层,永远存在,且不能通过名字检索活应用。通过org.apche.log4j.Logger类的静态方法getRootLogger()方法来得到,而其他的记录则通过org.apche.log4j.Logger类的静态方法getLogger(String name)来实例化。
Log4j还有两个特点,一是当我们用同样的名字调用 getLogger()方法,将总是返回同一个记录器的引用。这有利于我们在不用的代码或类中用同一个记录器记录日志信息。另一个是与自然界中祖先先于后代出现不同,一 记录器的祖先可以比后代的记录器出现得完,但是自动根据名字之间的关系建立这种家族关系。
记录器还有一个重要的属性——日志级别。日志级别一共分为五个级别,从低到高以此是:Debug、Info、Warn、Error和Fatal.他们分别在org.aptach.log4j.Level类中定义。不同的记录器可以有不同的级别。
日志级别的继承关系
记录器的名字 | 日志级别 | 继承的日志级别 | 最终的日志级别 |
root | Info | | Info |
x | Warn | | Warn |
x.y | none | Warn | Warn |
x.y.z | none | Warn | Warn |
在Logger类中定义了生成日志的信息的打印方法:
Debug()、Info()、Warn()、error()、fotal()个log()
Appender组件:
在Log4j中信息通过Appender组件输出到目的地,一个Appender实例就表示一个输出的目的地。目前,Appender支持将信息输出到文件、控制台、GUI组件、远程套接字服务器,JMS,NT事件记录器及远程Unix Syslog守护进程,信息可以被异步的输出。
一个记录器可以有多个Appender,通过调用Appender类的addAppender()方法来增加Appender记录器记录的每一个日志请求都会被送往它拥有的每一个Appender。Log4j提供了以下几种的Appender:
1).org.apache.log4j.ConsoleAppender ---将信息输出到控制台
2).org.apache.log4j.FileAppender -----将信息输出到文件
3).org.apache.log4j.DailyRollingFileAppender ----按照用户指定的日期和时间频率滚动产生日志文件。
4).org.apache.log4j.RollingFileAppender --- 当文件达到一定尺寸时,备份日志文件。
每个记录器都一个继承标记,用于记录记录器是否继承其父记录器的Appender,这个标记可以通过调用Logger类的setAddibivity(Bean additive)方法来设置,默认为true.需要注意的是,对于继承Appender的继承,是一种叠加性继承,而后代记录器只记录器父记录器的Appender,而不考虑更远的祖先情况,具体的继承规则如下:
记录器 的名字 | 添加的Appender | 继承/叠加标记 | 输出目标 |
root | A1 | | A1 |
x | A-x1,A-x2 | true | A1,A-x1,A-x2 |
x.y | none | true | A1, A-x1,A-x |
x,y,z | A-xyzl | true | A1, A-x1,A-x,A-xyzl |
a | A-al | false | A-al |
a.b | none | true | A-al |
a.b.c | A-al | true | A-al,A-al |
记录器a, 因为它的叠加性设为了false,所以就没有Appender的累加,另外要注意记录器a.b.c,它的Appender和a.b所继承的Appender同名,所以在输出信息时会同时输出两条消息。
Layout组件:
Layout组件负责格式化输出的日志信息,一个Appender只能有一个Layout.主要有如下几种Layout;
1).org.apache.log4j.SimplLayout -----将输出的消息格式化为自定义格式
SimpleLayout的输出由日志的级别+”-”+日志信息组成,例如:Debug-Hello
2)org.apache.log4j.HTMLLayout ------将输出的消息格式化为HTML
3)org.apache.log4j.XMLLayout ---Layout的输出由一系列在log4j.dtd中的定义的
4)org.apache.log4j.TTCCLayout ---TTCCLayout的输出由时间(time)、线程(thread)、类别(category)和嵌套的诊断上下文(context)信息组成。TTCC的命名就是由这4个英文单词的首字母组成的。
5).org.apache.PatternLayout ---PatternLayout提供了和C语言printf()一样的灵活性,程序员可以自定义输出的格式。例如:%r[%t]-5p%c - %m %n
我们在使用表中所列转换字符输出的日志信息的时候,如果还需要控制输出信息的最小宽度、最大宽度和对齐方式,可以使用可选的格式修饰符。可选的格式修饰符放置在%和转换字符之间。第一个可选的修饰符是减号(-)表示左对齐,后面可以直接十进制的常数,表示输出的最小字符,如果输出的数据比制定的字符还少,那么在字符的右边用空格填补;如果没有制定减号,表示右对齐,在数据的左边填补空格。如果超过了制定的最小的字符数,那么将按照实际长度输出。
格式修饰符的各种应用情况
格式修饰符 | 对齐方式 | 最小字符 | 最大字符 | 说明 |
%20c | 右对齐 | 20 | None | 如果类别的名字小于20个字符。在左边填充空格 |
%20-c | 左对齐 | 20 | None | 如果类别的名字小于20个字符。在右边填充空格 |
%.30c | NA | None | 30 | 如果类别的名字超过30个字符,那么超过的字符将从此处将被截断 |
%20.30c | 右对齐 | 20 | 30 | 如果类别的名字小于20个字符,那么在左边填充空格。如果类别的名字超过30个字符,那么超过的字符将从此处将被截断, |
%-20.30 | 左对齐 | 20 | 30 | 如果类别的名字小于20个字符,那么在左边填充空格。如果类别的名字超过30个字符,那么超过的字符将从此处将被截断 |
例如:
%d{yyyy-MM-dd HH:mm:ss} [%r] [%C] [%F] [%l] [%t] [%L] [%M] [%c]-[%-5p] %m%n
使用Log4j
使用Log4j总是采用以下三个步骤:
1).得到日志记录器,这个日志其将负责输出日志信息。对于跟记录器,通过调用getRootLogger()的静态方法它,其他的自记录器则通过getLogger(String name)方法来得到它。
2).读取配置文件:第二步是配置Log4j的运行环境。Log4j可以通过程序来配置,另外呢是用配置文件Log4j来配置文件。目前配置文件可以使用两种形式,一种是key=value的Java属性文件,一种是XML文件。不对环境做任何假定,特别是没有默认的Appender。在程序中设置Log4j有三种方法:
1).BasicConfigurator.configure(),这个方法为Log4j添加一个ConsoleAppender的实例,输出的信息将使用PatternLayout来格式化,格式化语句为 %r [%t] %p %c%x-%m%n;在默认情况下,根记录器的级别设置为Level.Debug,是最低的一级。
2)PropertyConfigurator.configure(String configFilename), 读取使用key=value方式编写的配置文件来设置Log4j的运行环境。
3).DomConfigurator.configure(String Filename);读取XML格式的配置文件来设置Log4j的运行环境。
Log4j的三种主要组件的配置:
1).配置根记录器,语法为:
Log4j.rootLogger=[level],[appenderName],[appenderName2],….. -----Level是制定日志的级别,可选值包括OFF,DEBUG,INFO,WARN,ERROR,FATAL和ALL,AppenderName制定Appender组件,可以为一个日志记录器制定多个Appender.
2).配置其他的记录器的语法为:
Log4j.logger.loggerName = [level],[appenderName],[appenderName2],…...
---loggerName是指定的记录器名字
配置appender组件:
Log4j.appender.AppenderName = 完整类名
配置Layout组件:
Log4j.appender.appenderName.layout.option1 = value;
使用web.xml配置文件配置Log4j的运行环境。
使用Log4j
实现步骤: 注意:各步骤之间都是相联系的。请参考实例代码……
Step1: 配置web应用的运行环境;通常是直接将log4j-1.2.14.jar包导入和或者复制到web目录下就行了。
Step2:修改DBExceptinoServlet.java
Step3:编写Log4j的配置文件。
Step4:编译DBExceptionServlet.java
Step5:部署Servlet
Step6:访问DBExceptionServlet.java
Step7:设置bookstorelogger的叠加性标签为false
Step8:设置RollingFileAppenderr
在更新了配置文件后要重新启动服务器,重新加载新的配置文件,在代码中可以用PropertyConfigurator.configureAndWatch()来替换PropertyConfiguartor.configure(); ConfigureAndWatch()方法将创建一个线程周期性的监测配置文件的改变。configureAndWatch()方法有两个重载:
1).public static void ConfigureAndWatach(String configureName)使用默认的时间间隔60秒来监测配置文件的更改
2).public static void ConfigureAndWatch(String configFilename,long delay) 可以在long delay指定每次检查的间隔时间,以毫秒为单位。
Step9:设置HTMLLayout
Step10:将日志信息保存到数据库中 请参考示例
Step11:将Log4j的配置文件改为XML文档格式 请参考示例
在修改了web.xml文件后,需要继续的修改DBExceptionServlet.java文件。将使用DOMConfigurator来操作。
NDC和MDC
在多用户并发的环境中,通常是由不同的线程分别处理不同的客户端请求,Web应用程序就是这样的一种应用。Log4j采用了能唯一地标识每个请求,用户要将标识请求的上下文信息放到诊断环境(NDC,Nested Diagnsotic Contex)中,在org.apache.log4j包里已经定义好了DNC类,这个类的所有方法都是静态的。 详情请参考该类
NDCl类在内部为每个线程单独维护了一个桟的数据结构,并以每一个线程对象作为key,对应的桟对象作为值,保存在散列表中。当servlet容器接收到访问Servelt的请求时,就分配一个线程为该请求服务,而在Servlet代码中,为该线程创建一个NDC桟(实际是在内部创建了一个java.Util.Stack类的对象),然后将可以标识请求的上下文信息保存到NDC桟中,该上下文可以是发出的请求的主机名、IP地址或其它任何可以标识该请求的信息。不同的客户端处理线程具有不同的NDC桟,即使这个Servlet有多个进程在运行也同样可以区分开来,在代码中使用NDC类的方法如下:
1).在进入一个环境时调用NDC.push()方法,如果当前的线程没有嵌套诊断环境,这个方法将建一个。
2).离开该环境时调用NDC.pop()方法。
3).当退出一个线程的时候,调用NDC.remove()方法,从这个线程中删除该诊断环境。在NDC的进入和离开的方法间调用的所有日志输出操作都被包含在当前线程的NDC桟的信息中。此过程不需要用户介入,我们只要在一些地方调用一下push()、pop()方法,将正确的信息放到NDC中就可以了。
4).MDC(Mapped Diagnostic Context)和NDC类似。只不过MDCS是基于map而不是基于栈。MDC在内部维护了一个散列表结构,通过java.unit.Hashtable类来实现。在org.apache.log4j包中,定义了MDC类,这个类的所有方法也是静态的。
MDC的类的方法如下:
Public class MDC{ Public static void put(java.lang.String ,java.lang.object); Public static java.lang.object get(java.lang.String); Public static void remove(java.lang.String); Public static java.unit.Hashtable getContext() ; } |
那么MDC类的使用:
…… MDC.put(“RemoteAddress”,res.getRemoteAddr()); ……日志操作语句 MDC.Get(“RemoteAddress”); MDC.remove(“RemoveAddress”); …… |
在配置文件中需要使用%X{key}转换模式,其中的Key,就是你在使用MDC.put()方法时使用的key,在上述的示例中是%x{RemoteAddress}
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/21228435/viewspace-580473/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/21228435/viewspace-580473/