log4j的使用(1)

log4j简介
    在应用程序中添加日志记录总的来说基于三个目的:监视代码中变量的变化情况,周期性的记录到文件中供其他应用进行统计分析工作;跟踪代码运行时轨迹,作为日后审计的依据;担当集成开发环境中的调试器的作用,向文件或控制台打印代码的调试信息。最普通的做法就是在代码中嵌入许多的打印语句,这些打印语句可以输出到控制台或文件中,比较好的做法就是构造一个日志操作类来封装此类操作,而不是让一系列的打印语句充斥了代码的主体。
   简单的说log4j就是帮助开发人员进行日志输出管理的API类库。它最重要的特点就是可以配置文件灵活的设置日志信息的优先级、日志信息的输出目的地以及日志信息的输出格式。
   Log4j除了可以记录程序运行日志信息外还有一重要的功能就是用来显示调试信息。程序员经常会遇到脱离java ide环境调试程序的情况,这时大多数人会选择使用System.out.println语句输出某个变量值的方法进行调试。这样会带来一个非常麻烦的问题:一旦哪天程序员决定不要显示这些System.out.println的东西了就只能一行行的把这些垃圾语句注释掉。若哪天又需调试变量值,则只能再一行行去掉这些注释恢复System.out.println语句。使用log4j可以很好的处理类似情况。
    一般的记录的样式为 [日志信息]-[操作开始的时间]-[日志级别]-[日志类别]-[用户名]-[操作名]-[消息]。

log4j的特性列表:

  • 在运行速度方面进行了优化
  • 使用基于名称的日志(logger)层次结构
  • 是fail-stop的
  • 是线程安全的
  • 不受限于预定义的实用工具集
  • 可以在运行时使用property和xml两种格式的文件来配置日志记录的行为
  • 在一开始就设计为能够处理Java异常
  • 能够定向输出到文件(file)、控制台(console)、java.io.OutputStream、java.io.Writer、远程服务器、远程Unix Syslog守护者、远程JMS监听者、NT EventLog或者发送e-mail
  • 使用DEBUG、INFO、WARN、ERROR和FATAL五5个级别
  • 可以容易的改变日志记录的布局(Layout)
  • 输出日志记录的目的地和写策略可以通过实现Appender接口来改变
  • 支持为每个日志(logger)附加多个目的地(appender)
  • 提供国际化支持


log4j使用方法
1.定义配置文件
   Log4j的初始化,通常使用配置文件灵活配置log日志的输出方式(输出优先级、输出目的地、输出格式)。
   Log4j支持两种配置文件格式,一种是XML 格式的文件log4j.xml,一种是Java特性文件log4j.properties(键=值)。
   需把log4j.jar和Log4j.properties(或者log4j.xml)放入classpath,log4j默认会在classpath中寻找log4j的配置文件。
  可指定配置文件位置如:
  set JAVA_OPTS=%JAVA_OPTS% -Dlog4j.configuration=
   或在程序中指定   log4j.xml  --PropertyConfigurator.configure()(DOMConfigurator.configure()).
                                  Log4j.properties --PropertyConfigurator.configure("String path");

2.组成部分
   Log4j中有三个主要的组件,它们分别是Logger、Appender和Layout.
   (1)logger指定log的名字,打印级别和采用哪种或者哪几种Appender。
   (2)Appender用来指明log信息打印到什么地方(如控制台,文件等).
   (3)Layout的作用是控制Log信息的输出格式.
  
2.1 配置Logger
log4j.rootLogger = [ level ] , appenderName, appenderName, …

    Logger的名称是区分大小写的,依据名称可以确定其层次结构(即父子关系),规则如下:
         如果Logger A的名称后跟一个点(.)是Logger B的名称的前缀就认为Logger A是Logger B的祖先。
         如果在Logger A和Logger B之间,Logger B没有任何其它的祖先就认为Logger A是Logger B的父亲。
    在Logger的层次结构的最顶层是rootLogger,它会永远存在,而且不能通过名字取到。 即 所有的logger都是继承于rootLogger,如果某个logger没有被分配level,那么它将从一个被分配了级别的最接近它的父logger那里继承level。因此在定义日志的时候通常会给rootLogger赋予一个level。

    level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。
    Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。
    appenderName就是指定日志信息输出到哪个地方。可同时指定多个输出目的地。

    Logger选择日志记录请求(log request)的规则:   
        假设Logger M具有q级的Level,这个Level可能是设置的也可能是继承到的。   
        如果向Logger M发出一个Level为p的日志记录请求,那么只有满足p>=q时这个日志记录请求才会被处理。
    比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来。

    另一种说法:
    当某个logger的logging request(即printing method(error(),info()..))的级别高于或者等于该logger的级别(即在log4j.properties或者 log4j.xml中定义)的时候,该logging request就为enable. 一旦该logger的logging request为enable,那么该logging request将总会打印到该logger所有的appender中包括它的所有父logger的appender。(而不会管父logger的级别如何)。除非该logger的父logger的additivity设置为false,默认的情况下为true。
    某个logger的additivity设置为false,表示log只打印到本log的appender中,而不再打印到其父logger的appender。

图示 1. Logger的层次结构图(附件中)
    Loger x.y是Logger x.y.z的祖先,因为x.y.是x.y.z的前缀,这符合规则的前一条。另外在Logger x.y和Logger x.y.z之间,Logger x.y.z没有其它的祖先,因此Logger x.y是Logger x.y.z的父亲,这符合规则的后一条。这样我们依据上面的规则就可以构造出如图1所示的Logger的层次结构。

    从图1中我们还可以看到每一个Logger都有一个Level,根据该Level的值Logger决定是否处理对应的日志请求。如果Level没有被设置,就象图1中的Logger x.y一样,又该怎么办呢?答案是可以从祖先那里继承。
    如 果Logger C没有被设置Level,那么它将沿着它的层次结构向上查找,如果找到就继承并结束,否则会一直查找到root logger结束。因为log4j在设计时保证root logger会被设置一个默认的Level,所以任何logger都可以继承到Level。
    图1中的Logger x.y没有被设置Level,但是根据上面的继承规则,Logger x.y继承了root logger的Level。


2.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(将日志信息以流格式发送到任意指定的地方)

    每个Logger可以有多个Appender,但是相同的Appender只会被添加一次。
    Appender的附加性意味着 Logger C会将日志记录发给它的和它祖先的所有Appender。在图1中Logger a会将日志记录发给它自己的JDBCAppender和它的祖先root logger的ConsoleAppender和FileAppender。Logger x.y.z自己没有Appender,它将把日志记录发给它的祖先root logger的ConsoleAppender和FileAppender,如果Logger x.y也含有Appender,那么它们也会包括在内。
    Appender的附加性是可以被中断的。假设Logger C的一个祖先为Logger P,如果Logger P的附加性标志(additivity flag)设置为假,那么Logger C会将日志记录只发给它的和在它和Logger P之间的祖先(包括Logger P)的Appender,而不会发给Logger P的祖先的Appender。Logger的附加性标志(additivity flag)默认值为ture。
    在图1中如果没有设置 Logger a的附加性标志(additivity flag),而是使用默认值true,那么Logger a会将日志记录发给它自己的JDBCAppender和它祖先root logger的ConsoleAppender和FileAppender,这和上面的描述相同。如果设置Logger a的附加性标志(additivity flag)的值false,那么Logger a会将日志记录发给它自己的JDBCAppender而不会在发给它祖先root logger的ConsoleAppender和FileAppender了。

2.3 配置layout  -- 日志信息的格式(布局)
    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)


3.在代码中使用Log4j
    (1)获取日志记录器,这个记录器将负责控制日志信息。
        public static Logger getLogger( String name) 
        log4j是线程安全的,所以一般建议定义logger时采用static
        通过指定的名字获得记录器,如果必要的话,则为这个名字创建一个新的记录器。Name一般取本类的名字,比如:
        static Logger logger = Logger.getLogger ( ServerWithLog4j.class.getName () ) ;

    (2)读取配置文件
当获得了日志记录器之后,第二步将配置Log4j环境,其语法为:
        BasicConfigurator.configure (): 自动快速地使用缺省Log4j环境。
PropertyConfigurator.configure ( String configFilename) :
            读取使用Java的特性文件编写的配置文件,但是要注意日志记录先前的配置不会被清除和重设。
        例:
                PropertyConfigurator.configure(".\\src\\log4j.properties")
        DOMConfigurator.configure ( String filename ) :读取XML形式的配置文件。

       注:在web程序中使用log4j注意问题
            --由于jsp或servlet在执行状态时没有当前路径概念,
            所以使用PropertyConfigurator.configure(String)语句找log4j.properties文件时,
            要给出相对于当前jsp或servlet的路径转化成为一个绝对的文件系统路径。
            方法是使用servletcontext.getrealpath(string)语句。如下:
            //得到当前jsp路径
            String prefix =  getServletContext().getRealPath("/");
            //读取log4j.properties
            PropertyConfigurator.configure(prefix+"\\WEB-INF\\log4j.properties");

            --相应的log4j.properties设置某个属性时也要在程序中设置绝对路径。例:
            log4j.appender.R.File属性设置日志文件存放位置。我们可以用读写.properties配置文件的方法进行灵活设置。

(3)插入记录信息(格式化日志信息)
    Logger.debug ( Object message ) ;
    Logger.info ( Object message ) ;
    Logger.warn ( Object message ) ;
    Logger.error ( Object message ) ;

4.性能优化:
    if  (logger.isDebugEnabled())
         {      log.debug("hello" + i + j);      }
    而不是直接在程序中调用:
    logger.debug("hello" + i + j);
    log类提供isTraceEnable()、isDebugEnable()、isInfoEnable()等判断当前调试级别是否大于设置级别,如果大于或等于则返回真。这样在logger打印条件不满足的情况下就不用执行字符串的操作。
    实际开发过程中,我们通常会使用Jakarta Commons Logging (JCL),它提供的是一个日志(Log)接口(interface),允许程序开发人员使用不同的具体日志实现工具:Log4J, JDK 1.4等。
    如果应用程序的classpath中有log4j, Commons Logging则使用相关的包装(wrapper)类(Log4JLogger)
    如果应用程序运行在jdk1.4的系统中, Commons Logging使用相关的包装类(Jdk14Logger)

5. 其他相关程序配置
    Log4j提供了BasicConfigurator,它只是为root logger添加Appender。其中,
  • BasicConfigurator.configure()为root logger添加一个关联着PatternLayout.TTCC_CONVERSION_PATTERN的ConsoleAppender
  • BasicConfigurator.configure(Appender appender)为root logger添加指定的Appender
    我们可以把BasicConfigurator看成是一个简单的使用程序配置Log4j环境的示例。
    例如,要给root logger添加两个Appender(A和B),下面的代码分别完成了这个要求。
    不使用BasicConfigurator:
        Logger root = Logger.getRootLogger();
        root.addAppender(A);
        root.addAppender(B);
    使用BasicConfigurator:
        BasicConfigurator.configure(A);
        BasicConfigurator.configure(B);

6.log4j.propertiest配置
Property文件是由key=value这样的键值对所组成的,可以使用#或!作为注释行的开始。下面给出了两个简单的示例:

非常简单的示例1:

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 %-5p [%t] %37c %3x - %m%n

稍显复杂的示例2:
log4j.rootLogger=, A1, A2
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %-5p [%t] %-17c{2}(%13F:%L)%3x - %m%n
log4j.appender.A2=org.apache.log4j.FileAppender
log4j.appender.A2.File=filename.loglog4j.appender.A2.Append=false
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%-5r %-5p [%t] %c{2} - %m%n   

注:log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
    上面只有INHERITED和NULL需要说明一下,其它部分和root logger相同。INHERITED和NULL的意义是相同的。如果我们使用了它们,意味着这个logger将不在使用自己的Level而是从它的祖先那里继承。
    Logger的附加性标志(additivity flag)可以使用log4j.additivity.logger_name=[false|true]来配置。

ObjectRenderer配置:我们可以通过ObjectRenderer来定义将消息对象转换成字符串的方式。语法为 log4j.renderer.fully.qualified.name.of.rendered.class=fully.qualified.name.of.rendering.class。如:
//my.Fruit类型的消息对象将由my.FruitRenderer转换成字符串
log4j.renderer.my.Fruit=my.FruitRenderer
对上面的各个配置元素的语法理解之后,在来看示例1和2就很容易了。
PropertyConfigurator不支持Filter的配置。
如果要支持Filter您可以使用DOMConfigurator,即使用XML文件的方式配置。

XML文件配置
要使用DOMConfigurator.configure()来读取XML格式的配置文件。
XML文件格式的定义是通过org/apache/log4j/xml/log4j.dtd来完成的,各个配置元素的嵌套关系如下:

这里没有给出更为详细的内容,要了解详细的内容需要查阅log4j.dtd。
下面这个简单的示例可以使您对XML配置文件的格式有一个基本的认识:

<o:p></o:p>

这里没有给出更为详细的内容,要了解详细的内容需要查阅log4j.dtd<o:p></o:p>

下面这个简单的示例可以使您对XML配置文件的格式有一个基本的认识:

 

这里没有给出更为详细的内容,要了解详细的内容需要查阅log4j.dtd。

下面这个简单的示例可以使您对XML配置文件的格式有一个基本的认识:

-<-!-ELEMENT log4j:configuration (renderer*, appender*,(category|logger)*,root?,categoryFactory?)->
这里没有给出更为详细的内容,要了解详细的内容需要查阅log4j.dtd。
下面这个简单的示例可以使您对XML配置文件的格式有一个基本的认识:
-<-?-xml version="1.0" encoding="UTF-8" -?->
-<-!-DOCTYPE log4j SYSTEM "log4j.dtd"->
-<-log4j->
 -<-appender name="A1" class="org.apache.log4j.FileAppender"->
 -<-layout class="org.apache.log4j.PatternLayout"->
 -<-param name="ConversionPattern" value="%-5p %c{2} - %m-n"-/->
 -<-/layout->
 -<-/appender->
 -<-appender name="A2" class="org.apache.log4j.FileAppender"->
 -<-layout class="org.apache.log4j.TTCCLayout"->
 -<-param name="DateFormat" value="ISO8601" -/->
 -<-/layout->
 -<-param name="File" value="warning.log" -/->
 -<-param name="Append" value="false" -/->
 -<-/appender->
 -<-category name="org.apache.log4j.xml" priority="debug"->
 -<-appender-ref ref="A1" -/->
 -<-/category->
 -<-root priority="debug"->
 -<-appender-ref ref="A1" -/->
 -<-appender-ref ref="A2" -/->
 -<-/root->
-<-/log4j>

默认初始化过程在LogManager类的静态初始化器中完成。具体步骤如下
    检查系统属性log4j.defaultInitOverride,如果值为false则执行初始化过程,否则跳过初始化过程。
    将系统属性log4j.configuration的值赋给变量resource。
    如果log4j.configuration没有被定义则使用默认值log4j.properties。     试图转换变量resource到一个url。   
    如果变量resource不能转换成一个url,
    那么将使用org.apache.log4j.helpers.Loader.getResource(resource, Logger.class)得到一个url。
    如果还是得不到url,将忽略默认初始化过程。
    如果得到url将使用PropertyConfigurator或DOMConfigurator来配置,也可以使用自定义的XXXConfigurator。
 
参考资料
图解 Tomcat 体系结构
Apache Log4j项目主页
Log4j Documentation,这里的资源非常的丰富。
一切源于网络,个人资料拼图,谢谢合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值