我们可以通过Yii的日志级别和信息分类进行归类,所选的信息还可以进一步设置信息路由到答不同的目的地,例如一个文件,数据库,Email,浏览器窗口等。
日志级别有:
* 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中进行配置,例子选择将日志存储在文件(系统默认为webapp\protected\runtime\application.log)中,为只存储trace和error级别,过滤以orange开始的log。
- ‘components’=>array(
- ……………
- ‘log’=>array(
- ‘class’=>‘CLogRouter’,
- ‘routes’=>array(
- array(
- ‘class’=>‘CFileLogRoute’,
- ‘levels’=>‘trace,error’,
- ‘categories’=>‘orange.*’
- ),
- ),
- ),
- ……………
- )
在控制器中定义方法并执行,在此为OrangeController控制器
- public function actionTest(){
- Yii::log(‘This is a trace log’,‘trace’,‘orange.test’);
- }
执行以后可在日志文件中看到我们的trace信息,为
- 2012/09/28 15:40:11 [trace] [orange.test] This is a trace log
- in D:\PHP\www\yii\orange\protected\controllers\OrangeController.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是如何反应的。
代码路径:framework\YiiBase.php#461
- public static function log($msg,$level=CLogger::LEVEL_INFO,$category=‘application’)
- {
- if(self::$_logger===null)
- self::$_logger=new CLogger;//如果_logger为null,则实例化Clogger类
- if(YII_DEBUG && YII_TRACE_LEVEL>0 && $level!==CLogger::LEVEL_PROFILE)
- {
- // YII_TRACE_LEVEL 设置backtrace 显示的内容条数,
- //这个常量会在debug_backtrace 函数返回信息中,获取指定条数,
- //如果为0(默认) 则为全部显示
- $traces=debug_backtrace();
- //debug_backtrace() 函数生成一个 backtrace,返回关联数组的数组,可以参考文档
- $count=0;
- foreach($traces as $trace)
- {
- if(isset($trace[‘file’],$trace[‘line’]) && strpos($trace[‘file’],YII_PATH)!==0)
- {
- $msg.=“\nin “.$trace[‘file’].‘ (‘.$trace[‘line’].‘)’;
- if(++$count>=YII_TRACE_LEVEL)
- break;
- }
- }
- }
- self::$_logger->log($msg,$level,$category);//调用_logger的方法处理日志
- }
主要功能就是上下2条语句。
2.CLogger的log方法
- class CLogger extends CComponent
- {
- const LEVEL_TRACE=‘trace’;
- const LEVEL_WARNING=‘warning’;
- const LEVEL_ERROR=‘error’;
- const LEVEL_INFO=‘info’;
- const LEVEL_PROFILE=‘profile’;
- …………………..
- public function log($message,$level=‘info’,$category=‘application’)
- {
- //保存日志(日志为一个数组,包括信息、级别、过滤、发生时间4内容)
- $this->_logs[]=array($message,$level,$category,microtime(true));
- //记录的日志个数自增1
- $this->_logCount++;
- //autoFlush为整数,表示在它们被刷新到目录前多少信息应该被记录。
- //默认到10,000, 意味着每10,000条信息,这个flush方法自动被发起一次信息。
- //如果为0,它意味着信息不会被自动刷新,一直保存到_logs[]中,直到调用raise onFlush事。
- //_processing表示我们是否正在处理log
- if($this->autoFlush>0 && $this->_logCount>=$this->autoFlush && !$this->_processing)
- {
- $this->_processing=true;
- //autoDump默认时,这个属性为false,意味着每次flush()日志之后已经过滤的信息仍然保存在内在中。
- //如果为true,已过滤的信息被保存在实际的媒介中
- $this->flush($this->autoDump);
- $this->_processing=false;
- }
- }
- ………………………
- public function flush($dumpLogs=false)
- {
- $this->onFlush(new CEvent($this, array(‘dumpLogs’=>$dumpLogs)));
- $this->_logs=array();//清空日志
- $this->_logCount=0;
- }
- public function onFlush($event)
- {
- //唤醒绑定在onFlush事件处理函数
- $this->raiseEvent(‘onFlush’, $event);
- }
- …………………………..
- }
3.绑定在onFlush事件处理函数
这是我们的CLogRouter就出场了,CWebApplication根据mian.php中的配置实例化CLogRouter,并执行其init方法
- class CLogRouter extends CApplicationComponent
- {
- private $_routes=array();
- public function init()
- {
- parent::init();
- foreach($this->_routes as $name=>$route)
- {
- //读取各个CLogRoute的配置,实例化
- $route=Yii::createComponent($route);
- //调用各个CLogRoute的init方法
- $route->init();
- //保存各个CLogRoute到_routes中
- $this->_routes[$name]=$route;
- }
- //给CLogger onFlush事件绑定处理函数,为本类的collectLogs方法
- Yii::getLogger()->attachEventHandler(‘onFlush’,array($this,‘collectLogs’));
- //给CWebApplication onEndRequest事件绑定处理函数,为本类的processLogs方法
- Yii::app()->attachEventHandler(‘onEndRequest’,array($this,‘processLogs’));
- }
- ……………………..
- //收集log
- public function collectLogs($event)
- {
- $logger=Yii::getLogger();
- $dumpLogs=isset($event->params[‘dumpLogs’]) && $event->params[‘dumpLogs’];
- foreach($this->_routes as $route)
- {
- if($route->enabled)
- //调用各个CLogRoute的collectLogs到记录所有日志的CLogger类中按照
- //自己的level和categories取出自己处理的log,也可立刻处理log(这也要看dumplogs的真假,为真则为立即处理)
- $route->collectLogs($logger,$dumpLogs);
- }
- }
- //收集处理log
- public function processLogs($event)
- {
- $logger=Yii::getLogger();
- foreach($this->_routes as $route)
- {
- if($route->enabled)
- //同上,但是此处为立刻处理log
- $route->collectLogs($logger,true);
- }
- }
- ………………
- }
4.调用各个CLogRoute处理日志,CLogRoute的collectLogs方法
- abstract class CLogRoute extends CComponent
- {
- public $levels=”;//过滤log用
- public $categories=”;//过滤log用
- ……………………
- public function collectLogs($logger, $processLogs=false)
- {
- //按照过滤条件到CLogger中去log
- $logs=$logger->getLogs($this->levels,$this->categories);
- $this->logs=empty($this->logs) ? $logs : array_merge($this->logs,$logs);
- //如果设置要立刻处理
- if($processLogs && !empty($this->logs))
- {
- if($this->filter!==null)
- Yii::createComponent($this->filter)->filter($this->logs);
- if($this->logs!==array())
- //处理
- $this->processLogs($this->logs);
- $this->logs=array();
- }
- }
- /**
- *处理日志信息并发送它们到指定的目标。 派生子类必须实现这个方法。
- *$logs为信息列表。每一个数组元素表示一个信息, 有下面的结构: array(
- *[0] => message (string)
- *[1] => level (string)
- *[2] => category (string)
- *[3] => timestamp (float, 从 microtime(true)获取)
- * )
- */
- abstract protected function processLogs($logs);
- ……………………
- }
其中CDbLogRoute实现方式为
- protected function processLogs($logs)
- {
- $command=$this->getDbConnection()->createCommand();
- foreach($logs as $log)
- {
- //遍历数组插入到数据库
- $command->insert($this->logTableName,array(
- ‘level’=>$log[1],
- ‘category’=>$log[2],
- ‘logtime’=>(int)$log[3],
- ‘message’=>$log[0],
- ));
- }
- }