Let's Log 4 net

Let's Log 4 Net

背景简介:

      日志功能对于任何一个服务级别的应用来说都是必不可少的,一个设计良好的日志功能可以为开发调试以及维护提供极大的便利,Log4J(Log4Net等)就是Apache的一套方便易用,而且扩展灵活的日志服务解决方案,官方网址: http://logging.apache.org/,Log4J简介: http://logging.apache.org/log4j/docs/manual.html
 

基本概念:

      由于我才接触Log4J,只是根据introduction的概念写了一个超轻量级的.net实现,所以这里只能讲讲我的理解,完整的log4j可以参看官方网站的pdf文档,内容庞大而且完整。
      Log4J里面最重要有三个主要类(或者说是接口,我定义时用的是interface),logger、appender和layout。Logger定义应用发送什么记录信息到日志服务,appender定义日志服务收到的信息如何存储(以及输出),layout定义输出日志的格式。
      一种典型的日志打印过程:应用发送一条error信息到logger,logger将这条信息发给自己关联的appender,appender使用layout将日志信息格式化后存入日志文件。
 

关联与继承:

      根据我的理解,Log4j中一个应用可以拥有多个logger,每个logger可以关联多个appender,而appender则与layout一一关联。
      对于每个logger,都一个唯一的标示名(类似URI),日志服务根据这个标示来获取指定的logger。在一个应用中,都有一个称之为root的Logger,该logger是应用中其他logger的基础,日志服务提供唯一的静态方法让用户获取这个logger(getRootLogger)。而对于系统中其他logger都有自己的父节点(parent logger),继承规则如下,对于名为 "akumaslab.a.b"的logger,它的默认parent logger名称应为"akumaslab.a",如果当前应用中没有这个logger,则"akumaslab.a.b"的parent logger被指定为root logger。
      应用中获取logger的方法如下(我自己的实现,仅供参考):
      //获取rootLogger
      ILogger root = LogService.getRootLogger();
      //获取名为"akumaslab.test"的logger
      ILogger log = LogService.getLogger("akumaslab.test");

     

      logger继承示例:

      root --- akumaslab.a --- akumaslab.a.b

              |                     /--- akumaslab.a.c

              /- anotherLogger

日志级别:

       Log4J中每一个logger都有自己的日志级别,默认的级别及优先级为:

       Fatal>Error>Warn>Info>Debug

       同时每个logger都提供这5个级别的日志写入方法,当应用输入日志信息时,logger会根据自己的级别判断是否将日志发送给appender。示例如下,我们假设log的级别为Warn:

      //Error >= log的级别(warn),该日志发给appender处理

      log.Error("error message");

      // Info < log级别(Warn),该日志被忽略

      log.Info("info message:);

      除了级别规则之外,logger还默认将有效的日志信息送往自己的父节点处(可设置参数禁止上送)。比如,当前应用中有4个节点"root" "akumaslab.a" "akumaslab.a.b" "another"(如前图),此时如果"akumaslab.a.b"收到一个有效的日志,则该条日志在"root"、"akumaslab.a"两个logger上也会被记录。


 实际用例:

       这里用几个我想到的用例来讨论如何有效的使用Log4J。
 
       用例1:
       为不同软件版本输出不同的日志信息。以前在c++等程序中,为了调试程序,经常在程序里面使用很多#if debug ....之类的语句,在debug模式时,增加日志打印。而在Log4J中,实现起来就非常简单,首先在应用中打印日志时,指明日志信息的级别:

      //Debug信息

      log.Debug("debug message");

      // Info,普通信息

      log.Info("info message:);

      发布程序时,如果要屏蔽掉应用中的全部debug日志,只要设置根logger的级别为Info,则所有Logger都不再打印Debug级别的日志(也可以调整config文件,而不用修改程序)。相反的,在debug时,只要设置为Debug就可打印全部debug日志。

      root = Logservice.getRootLogger();

      //设置Info级别,则应用中不再打印debug日志

      root.Level = LogLevel.Info;

 

      用例2:

      当一个应用中有多个模块,或者不同功能的线程同时工作时,如果将日志都打印到一个日志里,由于各模块的日志顺序交错,很难能分辨出单独模块具体的运行流程,而如果为各模块都各打印一个独立日志,则检查应用整体运行状况时,就会很难分析。利用Log4J,我们可以同时实现两种日志,而且不需要增加额外的日志打印指令。

      假设我们有两个模块A与B,需要将两个模块的日志分别保存在a.log和b.log,而且还要为应用程序生成一个完整的main.log。首先我们创建两个logger LoggerA、LoggerB,如下:

      root ------ LoggerA

               |--- LoggerB

      然后为a.log b.log main.log生成三个appender,分别绑定到3个Logger上,则关联关系如下:

      root(AppenderMain) ------- LoggerA (AppenderA)

                                      |--- LoggerB(AppenderB)

       由于默认情况下,logger会将日志信息送到父节点,所以两个模块日志的appender打印情况如下:

       模块A:appenderA appenderMain

       模块B:appenderB appenderMain

       通过这种方式,我们既在a.log b.log中为两个模块保存了各自的日志,又将合并的日志写入到了main.log。

 

       用例3:

       由于一个logger可关联多个appender,因此可以使日志同时输出到多个目标设备,包括文件、屏幕、控制台等,这个是log4J的基本功能,以下是我的部分实现代码:

       //一个泛型的appender列表

       List<ILogAppender> appenderList = new List<ILogAppender>();

       ...

       public void log(LoggerLevel msgLevel, object msg)
        {
            if (msgLevel>= this.level)
            { 

                ...              

                //日志有效,遍历appender进行输出

                foreach (ILogAppender appender in appenderList)
                {
                    appender.wrtieLog(Convert.ToString(level) + ":" + msg);
                }

 总结:

       其实Log4J实现起来并不困难,主要是设计人的构思让人佩服,简单明了的几个概念就可以组合成一套非常灵活的日志服务。相比之下,Sun领路的java阵营似乎越来越热衷于发明晦涩绕口的新名词,不过说实话老外脑子确实一根筋,本来英文单词表现力就不足,他们还只会缩写缩写再缩写,建议sun的老大们干脆来中国读两天小学,学学方块文字。所以如果哪天java社区改版成星象占卜八字命名学社区我也不会太奇怪,难怪IBM老大要考虑PHP了。
      PS:以上最后一段言论,专门针对Jini、JXTA等...
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值