技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 源码分析 --> Yii框架的Log系统的分析

Yii框架的Log系统的分析

浏览:2299次  出处信息

昨天阅读了Yii框架中log部分的源代码,框架提供了灵活、强大的log功能,如果不是非常特殊的需求,框架中自带的类就已经能够满足一般的应用的需求了。实现log功能的源代码被存放在/logging 目录下,这个目录下的代码都包含在包system.logging中。本文简要介绍一下我昨天阅读代码的所得。

system.logging 包类结构图

首先,来看一下这个图,这是Charles昨夜工作的结晶,研究了logging目录下一共九个文件中的类的关系。YiiBase,,CWebApplication不属于logging目录,但是为了说明这些类如何发生作用,也放在了这种图里。我的初衷,是要画一张标准的UML图的,无奈于本科的知识都还给老师了,所以这个图只能算是个四不像,大家凑合看一下,后面我会给自己补补课,后续的文章画得图会趋于规范的。

言归正传,左下角的类CLogger,是在开发过程中,打log时候,真正调用的类,这个类作为所有应用最最基础的组件,被包含在了YiiBase中,任何时候,在代码中调用Yii::getLogger()函数,会得到一个CLogger类的实例,这里用的是一个单件模式(Singleton)。打印log,只要调用其log()方法即可,这个方法有三个参数,第一个是log的内容,第二个是级别(warning,debug,fatal等),第三个category,可以叫类别,也可以视作是一种标识符,可以用于log的过滤。

Yii::getLogger()->log("here is a debug info.", 'debug','app.siteController');

上面的代码片段给出了一个打印log的范例,任何时候想打log,只要这样写就好。从上面的代码片段中,我们看到,log系统的调用接口是极其简单的。接下来分析一下大家非常关心的,log到底会被怎么处理的问题。

在框架中这个log系统里,负责打log,和负责记录log的是两个对象,他们被很好的解耦合了。CLogger扮演了一个专门生产log的角色,其任务就是将用户使用log()函数记录的log放到一个数组里,可以认为是一个内存buffer,长度可配置。在buffer满了的时候,会激发flush(如果配置了autoFlush)的话,flush就是冲掉的意思,如果内存buffer满了,则清空之,继续接受log信息。在清空log buffer之前,这个类对象会触发一个事件,就是onFlush事件,后续其他的类hook到这个onFlush事件上,就可以在log信息被清空之前,有所动作了。

  1.  public functionlog($message,$level='info',$category='application')

  2.     {//$this->_logs就是一个数组,也即存放log信息的内存缓冲,默认10000行

  3. $this->_logs[]=array($message,$level,$category,microtime(true));

  4. $this->_logCount++;

  5. if($this->autoFlush>0 && $this->_logCount>=$this->autoFlush)

  6. $this->flush(); //缓冲满了后,会调用flush

  7.     }

  8.     public function flush()

  9.     {

  10. $this->onFlush(new CEvent($this)); //激发onFlush事件

  11. $this->_logs=array(); //清空缓冲

  12. $this->_logCount=0;

  13.     }

  14. ?>

这是一个生产者与消费者的故事,以上讲述的是生产者的故事。接下来,讲消费者的故事。CLogger已经在内存中生产了log,那么接下来就要来收集,分析,处理这些log,该记录的记录,该抛弃的抛弃,该报警的报警。当然,你可以不给系统提供消费者,那些log产生了,然后消失了,基本不会带来什么负载和泄露,轻轻松松。

log的生产者是系统中必然存在的,但是log的消费者不是,是通过配置文件配置到系统中的,打开位于/protected/config/main.php的配置文件,在components段,我们可以看到关于log组件的配置,如下所示:

  1.  'log'=>array(

  2. 'class'=>'CLogRouter',

  3. 'routes'=>array(

  4.                 array(

  5.                     'class'=>'CFileLogRoute',

  6.                     'levels'=>'error, warning',

  7.                 ),

  8.                 // uncomment the following to show log messages on web pages

  9.                 /*

  10.                 array(

  11.                     'class'=>'CWebLogRoute',

  12.                 ),

  13.                 */

  14. ),

  15. ),

  16. ?>

负责采集处理log的真正对象,是一组以Route结尾的类,在上面类图中,位于右上角的那5个类。它们各有个的功能,发邮件的,写文件的,写Db的等等。前面也提了,对于一堆log,可能各自要使用不同的方法处理,比如debug信息抛弃,info信息记录在文件,而fatal信息发邮件给管理员,一个系统中很可能有这样那样的需求。所以,被以组件形式装进应用中的,并不是Route,而是类图中叫CLogRouter的对象。

对log的各种处理方法,都继承自一个叫CLogRoute的抽象类,提供了统一的调用接口,CLogRouter就是这些route的管理者,它主要负责的就是在onFlush事件发生的时候,把CLogger生产的log都接过来,然后,逐一地交付给自己旗下的Route们,分别处理。从上面的配置信息里,我们可以看到,LogRouter管理多少个Route也是通过配置文件配置的,也即route是router所依赖的组件。在具体开发过程中,你可以只配置一个,也可以配置一群。这种行为特征,真的有点像路由,怪不得叫router和route,我猜就这么个解释。

  1.  public function collectLogs($event)

  2.     {

  3. $logger=Yii::getLogger();

  4. foreach($this->_routes as $route)

  5. {//Router向每个route分发log,请求处理

  6. if($route->enabled)

  7.                 $route->collectLogs($logger,false);

  8. }

  9.     }

  10.     public function processLogs($event)

  11.     {

  12. $logger=Yii::getLogger();

  13. foreach($this->_routes as $route)

  14. {//Router向每个route分发log,请求处理

  15. if($route->enabled)

  16.                 $route->collectLogs($logger,true);

  17. }

  18.     }

  19. ?>

在操作实践中,我们完全可以自己继承CLogRoute,实现collectLogs方法,可以开发譬如名为NetLogRoute的类,将log从网络端口上以UDP包或者通过TCP连接形式发送到网络上专门的log服务器中,也可以开发名为MobileLogRoute的类,用来给管理员发送手机报警短信。

上面一直没有介绍到的Filter,其作用其实可以顾名思义,就是在log处理的时候,过滤用的,可以根据前文提到的category参数来过滤,也可以根据log等级类过滤,等等等等。Filter也是通过参数配置的形式被插入到route中的,完全可以创建自己特有的filter通过配置来替换默认filter,可以说,将灵活性发挥到了极致。不过,灵活还是有牺牲的,比如我就觉得,如果一个router下面挂上N个route之后,每个route都采用特定的filter,则会造成同一批log(10000条)被过滤的N遍。所以,比较好的模式,可能还是一个router,下面一个route,然后可以选择用或者不用filter,挂多个虽然理论可行,但是从实际代码来看,可能有一定性能损耗。

好了,终于嗦完了,最后问个问题,整个logging系统的这种结构,到底是哪一种设计模式呢?欢迎交流哈~

建议继续学习:

  1. Yii框架base包代码分析    (阅读:2548)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1