最近做了个小项目,客户把Log看的比业务都重要,不得已又要提高自己了,仔细研究了一下,终于从稀里糊涂里走出来了。
本文不打算详细的介绍Log4j, 所以,诸如Log的 level(级别), Appender (输出目的地),Layout(输出格式)以及打印参数等等, 不再熬述, 因为这样的文章网上一搜一麻袋,各位如果想找这方面的资料, 那就Google吧。
本文要说明的重点有两个:
1.如何利用Log4j将不同级别,不同package中Log输出到不同的文件中
2.Log4j的设置和package划分的关系
本文将从实战的角度出发,讲述本项目对Log输出的要求, 以及如何实现这样的要求, 希望对各位童鞋有用。
一.项目简介
环境:Eclipse
语言:Java
业务:分为Web系 和 Batch系两个模块
Package:
├─x
│ └─y
│ └─z
│ └─e
│ └─w
// 以下为Web系
│ ├─action│ │ └─interceptor
│ ├─dto
│ ├─entity
│ ├─exception
│ ├─hibernate
│ ├─listener
│ ├─service
│ └─util
// 以下为Batch系
│ ├─batch│ │ ├─bean
│ │ ├─conf
│ │ ├─exception
│ │ ├─query
│ │ └─util
// 其他
└─template└─simple
PS:
从上面的目录结构图不难看出, Web系和Batch系没有明确的分开,Batch系的Source全部在【bacth】package下面了, 但是Web系的Source却没有定义一个独立的package,而是散落在【w】package下面。
这是一个垃圾的设计,由于我一时的疏忽,没有考虑周全造成的。这会给Log4j的配置带来不必要的麻烦。在稍后会讲解它的弊端以及如何改善这个问题。
二.对Log输出的要求
1. 只输出DEBUG,INFO,ERROR三种级别的LOG
2. Web系的LOG分别输出到 web_debug.log, web_info.log, web_error.log 文件中
3. Batch系的LOG分别输出到 batch_debug.log, batch_info.log, batch_error.log 文件中
PS:注意Web系和Batch系是分开的,也就是说在Batch系的Log中不能出现Web系的Log,Web系的Log也不能出现在Batch系的Log中。
4. 每个Class,Method的预定动作,都会输出设计书规定的Log。
考虑到Framework采用Struts2 + Hibernate, 所以,Struts和Hibernate输出的Log,在项目发布时,预定关闭。
但是,要让客户能够轻而易举的将这两个OpenSource的Log打开。
但是,除此之外的其他第三方的OpenSource输出的Log,一律不准出现在Log文件中。
PS:客户对Log4j的了解为零(其实他也懂一点,但是他命令我把他当做傻瓜来看,这让我很为难,但我必须服从命令^_^)
// 其他打印格式等信息,此处省略,这不是本文讲述的重点
三.实现
- #--------------------------------------------------------------------
- #log4j.properties
- #--------------------------------------------------------------------
- # log4j.rootLogger = arg1, arg2, arg3,....
- # arg1 = ( DEBUG | INFO | WARN | ERROR | ALL | OFF | FATAL )
- # arg2,... is appender.
- #log4j.rootLogger = ERROR, C0, A0, A1, A2
- #In order to facilitate all levels of the log output can be flexible,
- #root logger is closed
- log4j.rootLogger = OFF
- #------------------------
- #Web Log
- #Level :
- # Followed from low to high is : ( DEBUG | INFO | WARN | ERROR | ALL | OFF | FATAL )
- # Higher than the current level log only will be output.
- #appender :
- # A0 : web debug log appender
- # A1 : web info log appender
- # A2 : web error log appender
- # C0 : web console log appender, currently is not being used.
- # if you want to use it, add it at log appender.
- # for example : log4j.logger.x.y.z.e.w.action = DEBUG, C0, A0, A1, A2
- # after used it, log information will be output to the console.
- #
- #------------------------
- # system log
- log4j.logger.x.y.z.e.w.action = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.action.interceptor = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.bean = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.dto = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.entity = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.exception = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.hibernate = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.listener = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.service = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.util = DEBUG, A0, A1, A2
- #hibernate log
- #hibernate log is closed, if you want to open it, use the following format .
- #log4j.logger.org.hibernate = arg1, arg2
- #arg1 : (DEBUG | INFO | WARN | ERROR | ALL | OFF | FATAL )
- #arg2 : A0, A1, A2
- log4j.logger.org.hibernate = OFF
- #struts2 log
- #struts log is closed, if you want to open it, use the following format .
- #log4j.logger.org.apache.struts2 = arg1, arg2
- #arg1 : (DEBUG | INFO | WARN | ERROR | ALL | OFF | FATAL )
- #arg2 : A0, A1, A2
- log4j.logger.org.apache.struts2 = OFF
- #------------------------
- # batch log
- # B0 : batch debug log appender
- # B1 : batch info log appender
- # B2 : batch error log appender
- #------------------------
- #system batch log
- log4j.logger.x.y.z.e.w.batch = DEBUG, B0, B1, B2
- #---------------------------------------------------------------------
- # Console
- # console appender is currently not being used, if you use it,
- # log information will be output to the console.
- # How to use it? -> in the corresponding log appender add it.
- # for example : log4j.logger.x.y.z.e.w.action = DEBUG, C0, A0, A1, A2
- log4j.appender.C0 = org.apache.log4j.ConsoleAppender
- log4j.appender.C0.Threshold = ALL
- log4j.appender.C0.layout = org.apache.log4j.PatternLayout
- log4j.appender.C0.layout.ConversionPattern=[%d{HH:mm:ss,SSS}][%-5p] (%F#%M:%L) - %m%n
- #---------------------------------------------------------------------
- # WEB DEBUG LOG
- log4j.appender.A0 = a.b.c.log4j.DailyRollingFileAppenderEx
- log4j.appender.A0.File = /var/log/web_debug.log
- log4j.appender.A0.Threshold = DEBUG
- log4j.appender.A0.append=true
- log4j.appender.A0.layout = org.apache.log4j.PatternLayout
- log4j.appender.A0.layout.ConversionPattern=[%d{HH:mm:ss,SSS}][%-5p] (%F#%M:%L) - %m%n
- #---------------------------------------------------------------------
- # WEB INFO LOG
- log4j.appender.A1 = a.b.c.log4j.DailyRollingFileAppenderEx
- log4j.appender.A1.File = /var/log/web_info.log
- log4j.appender.A1.Threshold = INFO
- log4j.appender.A1.append=true
- log4j.appender.A1.layout = org.apache.log4j.PatternLayout
- log4j.appender.A1.layout.ConversionPattern=[%d{HH:mm:ss,SSS}][%-5p] (%F#%M:%L) - %m%n
- #---------------------------------------------------------------------
- # WEB ERROR LOG
- log4j.appender.A2 = a.b.c.log4j.DailyRollingFileAppenderEx
- log4j.appender.A2.File = /var/log/web_error.log
- log4j.appender.A2.Threshold = ERROR
- log4j.appender.A2.append=true
- log4j.appender.A2.layout = org.apache.log4j.PatternLayout
- log4j.appender.A2.layout.ConversionPattern=[%d{HH:mm:ss,SSS}][%-5p] (%F#%M:%L) - %m%n
- #---------------------------------------------------------------------
- # BATCH DEBUG LOG
- log4j.appender.B0 = a.b.c.log4j.DailyRollingFileAppenderEx
- log4j.appender.B0.File = /var/log/batch_debug.log
- log4j.appender.B0.Threshold = DEBUG
- log4j.appender.B0.append=true
- log4j.appender.B0.layout = org.apache.log4j.PatternLayout
- log4j.appender.B0.layout.ConversionPattern=[%d{HH:mm:ss,SSS}][%-5p] (%F#%M:%L) - %m%n
- #---------------------------------------------------------------------
- # BATCH INFO LOG
- log4j.appender.B1 = a.b.c.log4j.DailyRollingFileAppenderEx
- log4j.appender.B1.File = /var/log/batch_info.log
- log4j.appender.B1.Threshold = INFO
- log4j.appender.B1.append=true
- log4j.appender.B1.layout = org.apache.log4j.PatternLayout
- log4j.appender.B1.layout.ConversionPattern=[%d{HH:mm:ss,SSS}][%-5p] (%F#%M:%L) - %m%n
- #---------------------------------------------------------------------
- # BATCH ERROR LOG
- log4j.appender.B2 = a.b.c.log4j.DailyRollingFileAppenderEx
- log4j.appender.B2.File = /var/log/batch_error.log
- log4j.appender.B2.Threshold = ERROR
- log4j.appender.B2.append=true
- log4j.appender.B2.layout = org.apache.log4j.PatternLayout
- log4j.appender.B2.layout.ConversionPattern=[%d{HH:mm:ss,SSS}][%-5p] (%F#%M:%L) - %m%n
这里对Log4j的设置做一下讲解:
讲解一. 第12行
- log4j.rootLogger = OFF
为什么将根Log关闭了呢? 因为所有的logger都会自动继承RootLogger,客户要求除Struts和Hibernate外的其他第三方OpenSource输出的Log,一律不准输出。
项目中使用了大量的其他第三方的OpenSource,RootLogger设定为OFF,所有使用Log4j的OpenSource都会自动继承RootLogger,被设定OFF。
除非再次显式的为它指定logger,否则,所有使用Log4j输出的Log都将不会输出,本项目中,在关闭RootLogger以后,就再次显式的指定了以下logger。
- log4j.logger.x.y.z.e.w.action = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.action.interceptor = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.bean = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.dto = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.entity = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.exception = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.hibernate = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.listener = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.service = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.util = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.batch = DEBUG, B0, B1, B2
这样一来,除上面明确指出的logger以外,其他所有的log都不会输出了。
当然还有下面两个Log:
- #hibernate log
- #hibernate log is closed, if you want to open it, use the following format .
- #log4j.logger.org.hibernate = arg1, arg2
- #arg1 : (DEBUG | INFO | WARN | ERROR | ALL | OFF | FATAL )
- #arg2 : A0, A1, A2
- log4j.logger.org.hibernate = OFF
- #struts2 log
- #struts log is closed, if you want to open it, use the following format .
- #log4j.logger.org.apache.struts2 = arg1, arg2
- #arg1 : (DEBUG | INFO | WARN | ERROR | ALL | OFF | FATAL )
- #arg2 : A0, A1, A2
- log4j.logger.org.apache.struts2 = OFF
这两个不写,也不会输出Log,因为他们会继承自RootLogger的OFF设定。
上面说了,客户要求预定将这两个Log关闭,必要的时候可以打开。看到上面蹩脚的英文说明没有,那是本人一级英语的杰作。尽管看上去都是废话,没办法,客户命令我把他当做傻瓜来看待。
讲解二.package 的划分与Log4j设置的关系
- # system log
- log4j.logger.x.y.z.e.w.action = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.action.interceptor = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.bean = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.dto = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.entity = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.exception = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.hibernate = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.listener = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.service = DEBUG, A0, A1, A2
- log4j.logger.x.y.z.e.w.util = DEBUG, A0, A1, A2
这一堆都是对Web系Log输出的控制,精确到了每一个package,没办法,我前面说过了,这个项目中对Web系package的划分是个垃圾的设计,因为他没有将Web系和Batch系的Source完全的分离开来, Web系的Source散落在package【w】下面,而RootLogger又被设定OFF,所以只能这样一个一个的设置了。
那么Web系的package改如何划分才对呢?很简单,只要在package【x.y.z.e.w】的下面再加入一层package,变为【x.y.z.e.w.web】就行了。
这样一来,Web系的package就全部在【x.y.z.e.w.web】的下面了,而Batch系的package已经在【x.y.z.e.w.batch】中了,上面那一堆对Web系Log的设置就可以改成这样了:
- # system log
- log4j.logger.x.y.z.e.w.web = DEBUG, A0, A1, A2
是不是简单多了!
好了,这篇文章就写到这里,希望能对童鞋们有所帮助。