A-A+

Yii Framework Log日志功能解析

2013年09月27日 PHP 评论 8 条

Yii使用层次的日志处理机制,即日志的收集与日志最终的处理(如显示、保存到文件、保存到数据数)是分离的。

日志信息的收集由CLogger(日志记录器)完成,而日志信息的分发处理,则在CLogRouter的调度(称为日志路由管理器)下,分发给处理对象(如CFileLogRoute以及logging目录下继承自CLogRoute的类, 称为日志处理器),经过反复阅读其源代码,我更是为Yii的设计思想所折服,如此的分层处理,使得其易于灵活扩展。日志信息有级别之分,如普通的info, profile, trace, warning, error级别,可以在日志路由中设置过虑条件,如设置CFileRoute的levels属性,即可只处理指定级别的日志信息。

如在程序中调用:
Yii::log($message,CLogger::LEVEL_ERROR,$category);

日志级别有:

* trace: 这是在 Yii::trace 中使用的级别。它用于在开发中 跟踪程序的执行流程。
* info: 这个用于记录普通的信息。
* profile: 这个是性能概述(profile)。下面马上会有更详细的说明。
* warning: 这个用于警告(warning)信息。
* error: 这个用于致命错误(fatal error)信息。

在 Yii 中,有下列几种日志路由可用:
* CDbLogRoute: 将信息保存到数据库的表中。
* CEmailLogRoute: 发送信息到指定的 Email 地址。
* CFileLogRoute: 保存信息到应用程序 runtime 目录中的一个文件中。
* CWebLogRoute: 将 信息 显示在当前页面的底部。
* CProfileLogRoute: 在页面的底部显示概述(profiling)信息。

信息可以通过 Yii::log 或 Yii::trace 记录。其 区别是后者只在当应用程序运行在 调试模式(debug mode) 中时才会记录信息。
Yii::log($message, $level, $category);
Yii::trace($message, $category);

示例:
需先在main.php中进行配置,例子选择将日志存储在文件(系统默认为webappprotectedruntimeapplication.log)中,为只存储trace和error级别,过滤以orange开始的log

01 'components'=>array(
02      ...............
03      'log'=>array(
04                'class'=>'CLogRouter',
05                'routes'=>array(
06                     array(
07                          'class'=>'CFileLogRoute',
08                          'levels'=>'trace,error',
09                          'categories'=>'orange.*'
10                     ),
11                ),
12           ),
13      ...............
14 )

在控制器中定义方法并执行,在此为OrangeController控制器

1 public function actionTest(){
2        Yii::log('This is a  trace log','trace','orange.test');
3    }

执行以后可在日志文件中看到我们的trace信息,为

1 2012/09/28 15:40:11 [trace] [orange.test] This is a  trace log
2 in D:PHPwwwyiiorangeprotectedcontrollersOrangeController.php (24)

Yii日志主要由CLogger,CLogRoute,CLogRouter三类来完成,其中CLogger在内存中记录日志信息,CLogRoute用不同的方式处理日志信息,CLogRouter将CLogger记录的信息发送给各个CLogRoute进行处理。类图如下:

在此简单介绍一下路由的整个过程:
1.Yii类中CLogger的实例化,调用 Yii::log(‘This is a trace log’,'trace’,'orange.test’);时,Yii类(其实是YiiBase是如何反应的。
代码路径:frameworkYiiBase.php#461

01 public static functionlog($msg,$level=CLogger::LEVEL_INFO,$category='application')
02      {
03           if(self::$_logger===null)
04                self::$_logger=new CLogger;//如果_logger为null,则实例化Clogger类
05           if(YII_DEBUG && YII_TRACE_LEVEL>0 &&$level!==CLogger::LEVEL_PROFILE)
06           {
07             // YII_TRACE_LEVEL 设置backtrace 显示的内容条数,
08             //这个常量会在debug_backtrace 函数返回信息中,获取指定条数,
09             //如果为0(默认) 则为全部显示
10                $traces=debug_backtrace();
11                //debug_backtrace() 函数生成一个 backtrace,返回关联数组的数组,可以参考文档
12                $count=0;
13                foreach($traces as $trace)
14                {
15                     if(isset($trace['file'],$trace['line']) &&strpos($trace['file'],YII_PATH)!==0)
16                     {
17                          $msg.="nin ".$trace['file'].' ('.$trace['line'].')';
18                          if(++$count>=YII_TRACE_LEVEL)
19                               break;
20                     }
21                }
22           }
23           self::$_logger->log($msg,$level,$category);//调用_logger的方法处理日志
24      }

主要功能就是上下2条语句。
2.CLogger的log方法

01 class CLogger extends CComponent
02 {
03      const LEVEL_TRACE='trace';
04      const LEVEL_WARNING='warning';
05      const LEVEL_ERROR='error';
06      const LEVEL_INFO='info';
07      const LEVEL_PROFILE='profile';
08      .......................
09     public function log($message,$level='info',$category='application')
10      {
11         //保存日志日志为一个数组,包括信息、级别、过滤、发生时间4内容)
12           $this->_logs[]=array($message,$level,$category,microtime(true));
13           //记录的日志个数自增1
14           $this->_logCount++;
15         //autoFlush为整数,表示在它们被刷新到目录前多少信息应该被记录。
16         //默认到10,000, 意味着每10,000条信息,这个flush方法自动被发起一次信息。
17         //如果为0,它意味着信息不会被自动刷新,一直保存到_logs[]中,直到调用raise onFlush事。
18         //_processing表示我们是否正在处理log
19           if($this->autoFlush>0 && $this->_logCount>=$this->autoFlush && !$this->_processing)
20           {
21                $this->_processing=true;
22             //autoDump默认时,这个属性为false,意味着每次flush()日志之后已经过滤的信息仍然保存在内在中。
23             //如果为true,已过滤的信息被保存在实际的媒介中
24                $this->flush($this->autoDump);
25                $this->_processing=false;
26           }
27      }
28   ...........................
29      public function flush($dumpLogs=false)
30      {
31           $this->onFlush(new CEvent($this, array('dumpLogs'=>$dumpLogs)));
32           $this->_logs=array();//清空日志
33           $this->_logCount=0;
34      }
35
36      public function onFlush($event)
37      {
38         //唤醒绑定在onFlush事件处理函数
39           $this->raiseEvent('onFlush', $event);
40      }
41 ................................
42 }

3.绑定在onFlush事件处理函数
这是我们的CLogRouter就出场了,CWebApplication根据mian.php中的配置实例化CLogRouter,并执行其init方法

01 class CLogRouter extends CApplicationComponent
02 {
03      private $_routes=array();
04      public function init()
05      {
06           parent::init();
07           foreach($this->_routes as $name=>$route)
08           {
09             //读取各个CLogRoute的配置,实例化
10                $route=Yii::createComponent($route);
11             //调用各个CLogRoute的init方法
12                $route->init();
13             //保存各个CLogRoute到_routes中
14                $this->_routes[$name]=$route;
15           }
16         //给CLogger onFlush事件绑定处理函数,为本类的collectLogs方法
17           Yii::getLogger()->attachEventHandler('onFlush',array($this,'collectLogs'));
18          //给CWebApplication  onEndRequest事件绑定处理函数,为本类的processLogs方法
19           Yii::app()->attachEventHandler('onEndRequest',array($this,'processLogs'));
20      }
21     ..........................
22      //收集log
23    public function collectLogs($event)
24      {
25           $logger=Yii::getLogger();
26           $dumpLogs=isset($event->params['dumpLogs']) && $event->params['dumpLogs'];
27           foreach($this->_routes as $route)
28           {
29                if($route->enabled)
30                     //调用各个CLogRoute的collectLogs到记录所有日志的CLogger类中按照
31                    //自己的level和categories取出自己处理的log,也可立刻处理log(这也要看dumplogs的真假,为真则为立即处理)
32                     $route->collectLogs($logger,$dumpLogs);
33           }
34      }
35   //收集处理log
36      public function processLogs($event)
37      {
38           $logger=Yii::getLogger();
39           foreach($this->_routes as $route)
40           {
41                if($route->enabled)
42                     //同上,但是此处为立刻处理log
43                     $route->collectLogs($logger,true);
44           }
45      }
46 ..................
47 }

4.调用各个CLogRoute处理日志,CLogRoute的collectLogs方法

01 abstract class CLogRoute extends CComponent
02 {
03        public $levels='';//过滤log
04        public $categories='';//过滤log
05        ........................
06       public function collectLogs($logger, $processLogs=false)
07      {
08           //按照过滤条件到CLogger中去log
09           $logs=$logger->getLogs($this->levels,$this->categories);
10           $this->logs=empty($this->logs) ? $logs : array_merge($this->logs,$logs);
11           //如果设置要立刻处理
12           if($processLogs && !empty($this->logs))
13           {
14                if($this->filter!==null)
15                     Yii::createComponent($this->filter)->filter($this->logs);
16                if($this->logs!==array())
17                     //处理
18                     $this->processLogs($this->logs);
19                $this->logs=array();
20           }
21      }
22
23      /**
24      *处理日志信息并发送它们到指定的目标。 派生子类必须实现这个方法。
25      *$logs为信息列表。每一个数组元素表示一个信息, 有下面的结构: array(
26      *[0] => message (string)
27      *[1] => level (string)
28      *[2] => category (string)
29      *[3] => timestamp (float, 从 microtime(true)获取)
30      *  )
31      */
32      abstract protected function processLogs($logs);
33   ........................
34

其中CDbLogRoute实现方式为

01 protected function processLogs($logs)
02     {
03          $command=$this->getDbConnection()->createCommand();
04          foreach($logs as $log)
05          {
06               //遍历数组插入到数据库
07               $command->insert($this->logTableName,array(
08                    'level'=>$log[1],
09                    'category'=>$log[2],
10                    'logtime'=>(int)$log[3],
11                    'message'=>$log[0],
12               ));
13          }
14     }
标签:

8 条留言  访客:8 条  博主:0 条

  1. 不锈钢网

    不错的文章,内容无懈可击.禁止此消息:nolinkok@163.com

  2. 荷兰网

    不错的文章,内容见缝插针.禁止此消息:nolinkok@163.com

  3. 安平物流网

    好文章,内容无懈可击.禁止此消息:nolinkok@163.com

  4. 石笼网

    不错的文章,内容层次清晰.禁止此消息:nolinkok@163.com

  5. 石笼网箱

    好文章,内容气势磅礴.禁止此消息:nolinkok@163.com

  6. 压滤机

    好文章,内容无与伦比.禁止此消息:nolinkok@163.com

  7. 士大夫

    不错的文章,内容无与伦比.禁止此消息:gov_sb@qq.com 黑客 http://www.fbisb.com/

  8. 玻璃钢管道

    好文章,内容字字珠玉.禁止此消息:nolinkok@163.com

给我留言

Copyright © 破晓Web实验室 保留所有权利.   Theme  Ality 沪ICP备14044094号

用户登录