欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Yii的log分析

程序员文章站 2024-03-22 09:23:46
...
我们可以通过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进行处理。类图如下:
[img]http://dl.iteye.com/upload/attachment/0074/5181/2002c055-709b-3337-89b8-181024053831.png[/img]
在此简单介绍一下路由的整个过程:
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],
));
}
}
相关标签: Yii