CONAN ZONE

你越挣扎我就越兴奋

BlogJava 首页 新随笔 联系 聚合 管理
  0 Posts :: 282 Stories :: 0 Comments :: 0 Trackbacks
由于自己工作性质发生了些变化,人随境迁,回首时,发现真的是岁月如梭,时光如水。弹指间,从研发到维护,从总部到出差已经是四月有余了。

    在维护系统时,难免会时不时地跟代码再次打些交道。今天想再操刀做个小工具时,居然不太记得了log4j的配置,不得不从apache再重新down了相关的jar与DOC,匆匆看看了一下,快点写下来,日后肯定还用得着,同时也希望对网友们有用。 

    Log4j基本上已经是java里的首选日志工具了,它主要由三部分组成:Loggers, Appenders和Layouts (注意后面都加了s啦,顾名思义一个配置中可以分别允许有多个此类对象存在,后面将详细介绍)。

    Loggers-用来定义日志消息的类型及级别;

    Appenders-用来定义日志消息的输出终端;

    Layouts-用来定义日志消息的输出格式。

  
   
Logger

    Loggers层次:

    logger的名字是大小写敏感。

规则-如果类P的名字是另一个类C的名字的前缀,且P与C之间以“.”号连接起来,那么称P为祖先层次;如果层次A与其子层次之间没有任何父层次,则认为层次A为父层次。

    例如,org.apache.log4j是org.apache.log4j.Logger的父层次;而org.apache是org.apache.log4j与org.apache.log4j.Logger的祖先层次。

    另外,注意log4j中有个默认的root级别的logger,在所有logger中,它是最高级别,其它所有logger均继承于root,root有以下二个特性:

    1. 它总是存在的。

    2. 它不能通过名字直接获取其实例(root实例可以通过类Logger的静态方法Logger.getRootLogger获得,而其它logger则可以直接通过名字来获取Logger.getLogger)。

    关于Loggers中的级别:

   对每个logger,可以指定其级别,在系统org.apache.log4j.Level中,已经定义了五个级别,分别为debug, info, warn, error, fatal。

规则-设当前logger为X,从X开始往X的父类方向开始算(包括X本身),直到名为root的logger,第一个不为null的级别值就是X的级别值。

    日志显示:  
    
级别的定义是为了过滤性地选择日志。

规则-若当前请方式级别为P,而当前的logger的级别为Q,当且仅当在P>=Q的情况下,日志信息才能显示。


   
关于日志中级别的关系为:DEBUG < INFO < WARN < ERROR < FATAL
    关于此规则的说明,有以下代码为实例:   

// get a logger instance named "com.foo"

   Logger logger = Logger.getLogger("com.foo");

   // Now set its level. Normally you do not need to set the

   // level of a logger programmatically. This is usually done

   // in configuration files.

   logger.setLevel(Level.INFO);

   Logger barlogger = Logger.getLogger("com.foo.Bar");

   // This request is enabled, because WARN >= INFO.

  logger.warn("Low fuel level.");

   // This request is disabled, because DEBUG < INFO.

   logger.debug("Starting search for nearest gas station.");

   // The logger instance barlogger, named "com.foo.Bar",

   // will inherit its level from the logger named

   // "com.foo" Thus, the following request is enabled

   // because INFO >= INFO.

   barlogger.info("Located nearest gas station.");

   // This request is disabled, because DEBUG < INFO.

   barlogger.debug("Exiting gas station search");

Appenders与Layouts

Appender正如前面所述,是用来定义日志信息的输出终端,最觉的输出终端有console与file了,另外还有其它如GUI components, JMS, NT Event Loggers, remote socket servers等等。

    Appender也有类似继承的原则,即当前logger的appender包括其它父类的appender。这样就会出现一个logger可能拥有多个appender了,在现实中看来,就是log4j的日志信息可以同进输出到console, file等等终端了。当然,为了不使此appender恶性叠加,可以通过设置additivity标志来阻止继承。

    规则-若当前logger为C,则C拥有包括其自己及其父类的所有appender。另外,若C的父logger为P,且P的additivity标志已经设置成为false,则C只拥有自己及P的appender了,而P则只能拥有本身的appender。

    以下表格可以清晰说明此规则:
    
Logger
Name
Added
Appenders
Additivity
Flag
Output Targets Comment
root A1 not applicable A1 The root logger is anonymous but can be accessed with the Logger.getRootLogger() method. There is no default appender attached to root.
x A-x1, A-x2 true A1, A-x1, A-x2 Appenders of "x" and root.
x.y none true A1, A-x1, A-x2 Appenders of "x" and root.
x.y.z A-xyz1 true A1, A-x1, A-x2, A-xyz1 Appenders in "x.y.z", "x" and root.
security A-sec false A-sec No appender accumulation since the additivity flag is set to false.
security.access none true A-sec Only appenders of "security" because the additivity flag in "security" is set to false.
    
    
    对于layout,也正如前面所述,是用来定义日志信息的输出格式,它的与C语言中
printf函数的格式定义基本相似,本人对printf中的格式参数不太熟悉,总感觉有些复杂,一般是平时看到自己认为有用的格式就记一下,到时直接搬过来。如

log4j.appender.R.layout.ConversionPattern=--->%-d{yyyy-MM-dd HH:mm:ss} [%5p]%l - %m%n

时,日志信息格式为:

--->2008-07-11 01:13:40 [ INFO]com.test.Log4jTest.main(Log4jTest.java:27) - Exiting application.

    
    好啦,现在log4j的理论很肤浅地扯了一下,现在可以开始配置了。

   配置:   

    Log4j
的配置可以通过加载Java的properties配置文件或者XML文件来完成。

    Log4j默认的配置为,通过读取系统变量log4j.configuration来找到配置文件,当然变量的默认值为log4j.properties,所以若没有设置此系统变量,可以直接将配置文件命名为log4j.properties,然后放到类路径下即可。另外,若想引用通过其它配置文件,则可以通过

    Loader.getResource(java.lang.String)来读取指定的配置文件。

    其它:

    1. 由于有了log4j中的级别继承机制,所以可以很方便地过滤信息了,不仅可以很方便地限制日志的输出量,也可以同时将日志输出到不同的终端。
    另外,因为在java文件中,文件的物理层次关系也是直接通过“.”符号来控制的,且在很在程度上这个物理层次也决定了文件的逻辑层次,所以我们在当前文件中获取logger时,可以直接通过当前文件的类名来获取,如:
    
    static Logger logger = Logger.getLogger(MyApp.class);
    这样,在过滤消息时就很简单了,简单示例如下:
    在配置文件中有
    log4j.rootLogger=ERROR,stdout,R
    log4j.category.com.db=DEBUG
    log4j.category.com.i18n=INFO
    log4j.category.com.zyx=fatal

    默认的root logger的日志级别为Error,根据级别关系这个级别也相当高了,这样可以减少系统中日志的输出量,但有些地方可能得输出更详细信息,如数据库部分,所以可以将com.db设置成了debug。另外,我在com.zyx下,我只想看到类型为fatal的日志,也可以如上所设。

 

    2. log4j.rootLogger=ERROR,stdout, ROLLING_FILE这个定义表示root logger的日志级别为Error,后面的stdout, ROLLING_FILE表示此root有二个appender,通常可以通过这样来定义日志可以同时向多个终端输出,因为子logger可以继承所有父logger的appender.

    如我可以通过以下定义将日志同时往console及file输出:

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=--->%-d{yyyy-MM-dd HH:mm:ss} [%5p]%l - %m%n

 

log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender

log4j.appender.ROLLING_FILE.File=myapp.log

log4j.appender.ROLLING_FILE.Append=true

log4j.appender.ROLLING_FILE.MaxFileSize=1024KB

log4j.appender.ROLLING_FILE.MaxBackupIndex=10

log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout

log4j.appender.ROLLING_FILE.layout.ConversionPattern==[slf5s.start]%d{DATE}[slf5s.DATE]%n"

   %p[slf5s.PRIORITY]%n%x[slf5s.NDC]%n%t[slf5s.THREAD]%n"

   %c[slf5s.CATEGORY]%n%l[slf5s.LOCATION]%n%m[slf5s.MESSAGE]%n%n

 

    马马虎虎总结了一下,但也花费了二个多小时,呵呵!

posted on 2008-07-11 09:13 CONAN 阅读(172) 评论(0)  编辑  收藏 所属分类: JAVA