LOG4J-日志工具包
log4j有记录器(loggers)、输出源(appenders)、级别(levels)、布局(layouts)4个部分组成。
1,记录器
?? ?调用log4j的logger.getLogger()方法将会得到一个logger的实例。如果一个应用中能够包含了上千个类,那么几乎需要上千个logger实例。
如何对这上千个logger实例进行方便地配置,就是一个很重要的问题。log4j采用了一种树状的继承层次关系,它们有一个共同的根,位于最上层。?
2,输出源
?? ?输出源可以是控制台、文本文件、xml文件、socket、windows事件日志、Eamil,这些相关的处理类是ConsoleAppender、FileAppender、SocketAppender、
NtEventLogAppender、SMTPAppender。我们常用的输出源是文本文件。?
3,级别
?? ?log4j内置5种日志级别为: DEBUG(调试) < INFO(信息) < WARN(警告) < ERROR(错误) < FATAL(致命错误)?
4,布局
?? ?log4j采用了类似C语言中的printf()函数的打印格式对日志信息进行格式化,打印参数如下:
?? ?%m ?输出代码中指定的信息
?? ?%p ?输出日志级别,即DEBUG、INFO等
?? ?%r ?输出自应用启动到输出该日志信息耗费的毫秒数
?? ?%c ?输出所属的类目,通常是所在类的全名,如果加上{<层数>}表示列出从最内层算起的指定层数的名字空间。
?? ?%C ?输出所属的类目,通常是所在类的简名
?? ?%t ?输出产生该日志事件的线程名
?? ?%n ?输出换行符
?? ?%d ?输出日志时间,默认格式是ISO8601,也可自定义,如:%d{yyyy MM dd HH:mm:ss,SSS} ,输出为:2011 10 18 22:10:28,921?
?? ?%L ?输出日志事件在代码中的行号
?? ?%i ?输出日志事件的类目名、线程名、行号
?? ?%F ?输出文件名
?? ?%x ?按NDC(Nested Diagnostic Context,线程堆栈)顺序输出日志
?? ?%X ?按MDC(Mapped Diagnostic Context,线程映射表)输出日志。
?
5,配置
?? ?log4j.properties
?? ?log4j.appender.normallog=org.apache.log4j.DailyRollingFileAppender #可定义单个文件最大值,在每日零点自动归档
?? ?log4j.appender.normallog.layout=org.apache.log4j.PatternLayout
?? ?log4j.appender.normallog.layout.ConversionPattern=%d %5p [%t](%F:%L)-%m%n
?? ?log4j.appender.normallog.File=mylog.log
?? ?log4j.appender.normallog.DatePattern='.'yyyy-MM-dd?
?? ?log4j.rootlogger=info,normallog
?? ?log4j是利用类装载器(ClassLoader)查找配置文件的,提高了系统的可移植性。
?
?6,执行顺序
?? ?loger.info() -> Log4JLogger.info() ->Category.log(),forcedLog,callAppenders ->AppenderAttachableImpl.appendLoopOnAppenders() ->
?? ?ConsoleAppender.doAppend()->AppenderSkeleton.doAppend()->WriterAppender.append(),subAppend -> PatternLayout.format()
?? ?注: PatternLayout实例化时,构建PatternParser,并执行parse方法。
?? ? ? ?PatternLayout.format时,执行PatternConverter的format方法和convert方法。
?
?7,自定义layout
?? ?a,定义PatternLayout类,继承PatternLayout类,重写createPatternParser方法和构造函数,如:org.jboss.logging.layout.PatternLayout
?? ?b,定义PatternParser类,继承PatternParser,重写finalizeConverter方法和构造函数,如:org.jboss.logging.layout.PatternParserEx
?? ?c,定义PatternConverter类,继承PatternConverter,重写convert方法和构造函数,如:org.jboss.logging.layout.ThreadNDCConverter
//返回当前调用线程的ID
@Override
protected String convert(LoggingEvent event) {
return String.valueOf(Thread.currentThread().getId());
}
?
8,NDC和MDC
?? ? ?NDC(Nested Diagnostic Context)和MDC(Mapped Diagnostic Context)是log4j种非常有用的两个类,它们用于存储应用程序的上下文信息(context infomation),从而便于在log中使用这些上下文信息。?
?? ? ?NDC采用了一个类似栈的机制来push和pop上下文信息,每一个线程都独立地储存上下文信息。比如一个servlet就可以针对每一个request创建对应的NDC,储存客户端地址等等信息。当使用的时候,我们要尽可能确保在进入一个context的时候,把相关的信息使用NDC.push(message);在离开这个context的时候使用NDC.pop()将信息删除。另外由于设计上的一些问题,还需要保证在当前thread结束的时候使用NDC.remove()清除内存,否则会产生内存泄漏的问题。在最新的log4j 1.3版本中增加了一个org.apache.log4j.filters.NDCMatchFilter,用来根据NDC中存储的信息接受或拒绝一条log信息。?
?? ? ?MDC和NDC非常相似,所不同的是MDC内部使用了类似map的机制来存储信息,上下文信息也是每个线程独立地储存,所不同的是信息都是以它们的key值存储在”map”中。相对应的方法,MDC.put(key, value); MDC.remove(key); MDC.get(key); 在配置PatternLayout的时候使用:%x{key}来输出对应的value。同样地,MDC也有一个org.apache.log4j.filters.MDCMatchFilter。MDC是线程独立的,但是一个子线程会自动获得一个父线程MDC的copy。至于选择NDC还是MDC要看需要存储的上下文信息是堆栈式的还是key/value形式的。
?