Yii2 log分析

体验yii2的log功能

  1. 创建一个yii2的应用
  2. 在@app/Controllers目录新建一个TestController, 在控制器里新建一个actionIndex方法

    class TestController extends Controller{ public function actionIndex() { } } 

    注:@app是yii2中的路径别名语法,表示应用的基础目录

  3. 在actionIndex方法中写日志

    ...
    public function actionIndex() { //记录一个错误级别的日志 Yii::error('人艰不拆!'); } ... 
  4. 进入yii2应用的日志目录@runtime/logs, 看到生成了一个名为app.log的文件, 内容如下:

     //日志产生时间  访问者ip地址 用户id SESSIONID 日志级别 日志类别  日志内容  
    1 2014-12-04 12:27:26 [10.18.60.111][-][-][error][application] 人艰不拆! //trace记录 2 in /home/zhangjiulong/project/hulk_log/controllers/TestController.php:18 

yii2-log调用支持不同的报警级别

  1. 警告级别 WARNING

    public function actionIndex() { //记录一个警告级别的日志(日志内容可以为任何数据类型) Yii::warning(['source'=>'关电总局','content'=>'不能看美剧了']); } 

    日志输入结果

    3 2014-12-04 14:23:32 [10.18.60.111][-][-][warning][application] [ 4 'source' => '关电总局', 5 'content' => '不能看美剧了', 6 ] 7 in /home/zhangjiulong/project/hulk_log/controllers/TestController.php:18 
  2. 提示级别 INFO

    //记录一个提示级别的日志
    Yii::info('喝酸奶只舔盖,我就是这么任性!');
    
  3. 代码追踪级别 TRACE
    //记录一个trace级别的日志
    Yii::trace('我这个级别,一般是在开发环境使用');
    

    trace级别的日志,只会在dev开发环境下才会触发, 所以Yii::trace方法中做了如下判断

     ...
     public static function trace($message, $category = 'application') { if (YII_DEBUG) { //只有开发环境(YII_DEBUG为true)才会触发 static::getLogger()->log($message, Logger::LEVEL_TRACE, $category); } } ... 

yii2-log支持不同的日志类别(如果你想将不同类型的日志写入不同文件的中)

比如你想把与db相关的日志都写入到sql.log文件中

  1. 打开应用的配置文件@app/config/web.php, 在log组件的targets属性数组中添加一个"target"对象

    ...
    'components' => [
         ...
         'log' => [
             'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ [ 'class' => 'yii\log\FileTarget', 'levels' => ['error', 'warning','info','trace','profile'], 'logVars'=>[], //除了except对应的分类之外,其他的都写入到 'except'=>['yii\db\*','app\models\*'] ], //在原配置的基础上,增加以下配置(新增一个target) [ 'class' => 'yii\log\FileTarget', 'levels' => ['error', 'warning','info','trace','profile'], 'logVars'=>[], //表示以yii\db\或者app\models\开头的分类都会写入这个文件 'categories'=>['yii\db\*','app\models\*'], //表示写入到文件sql.log中 'logFile'=>'@runtime/logs/sql.log', ], ], ], ... ], ... 
  2. 调用的时候,只需要加上第二个参数,填写对应的分类即可

    public function actionIndex() { //日志的第二个参数就是分类category Yii::info('select * from table', 'yii\db\Query'); } 
  3. 进入@runtime/logs下,可以看到生成了一个sql.log的文件

    └── logs
     ├── app.log
     └── sql.log
    //sql.log内容如下
    2014-12-05 18:58:51 [10.18.60.111][-][-][info][yii\db\Query] select * from table 2 in /home/zhangjiulong/project/hulk_log/controllers/TestController.php:16 

yii2-log支持按时间来保存日志

  1. 打开应用的配置文件@app/config/web.php, 在log组件的target的logFile属性,日志文件名带上时间后缀即可
    ...
    'components' => [
         ...
         'log' => [
             'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ [ 'class' => 'yii\log\FileTarget', 'levels' => ['error', 'warning','info','trace','profile'], 'logVars'=>[], //表示以yii\db\或者app\models\开头的分类都会写入这个文件 'categories'=>['yii\db\*','app\models\*'], //表示写入到文件sql.log.2014xxxx 'logFile'=>'@runtime/logs/sql.log.'.date('Ymd'), ], ], ], ... ], ... 
    2.再次使用Yii::info('select * from table', 'yii\db\Query');, 你会看到日志目录里
    logs
    ├── app.log
    ├── sql.log └── sql.log.20141208 

yii2-log支持将日志记录到数据库

  1. 需要先按下面的格式创建一个log表,日志名称可自定义,默认为log
CREATE TABLE log (
    id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, level INTEGER, category VARCHAR(255), log_time INTEGER, prefix TEXT, message TEXT, INDEX idx_log_level (level), INDEX idx_log_category (category) ) 
  1. 打开应用的配置文件@app/config/web.php, 在log组件的targets中新增一个target----DbTarget
    ...
    'components' => [
         ...
         'log' => [
             'traceLevel' => YII_DEBUG ? 3 : 0, 'targets' => [ ... [ 'class' => 'yii\log\DbTarget', //DbTaget类表示将日志记录到数据库中 'levels' => ['error', 'warning','info'], 'logVars'=>[], 'logTable'=>'log',//logTable表示要记录日志的表名,默认为log ], ... ], ], ... ], ... 
  2. 此时当你再次使用Yii::info('切克闹');, 所以符合条件的target都会记录这条信息

    在表log中会插入一条数据

+----+-------+-------------+------------+----------------------+-----------+
| id | level | category    | log_time   | prefix               | message   |
+----+-------+-------------+------------+----------------------+-----------+
| 11 |     4 | application | 1418010724 | [10.18.60.111][-][-] | 切克闹 | 
+----+-------+-------------+------------+----------------------+-----------+
1 row in set (0.00 sec)

在app.log文件中会追加一条数据

2014-12-08 11:52:03 [10.18.60.111][-][-][info][application] 切克闹 180 in /home/zhangjiulong/project/hulk_log/controllers/TestController.php:16 

yii2-log除了支持记录到文件和数据库,还可以直接发送邮件yii\log\EmailTarget,记录到syslogyii\log\SyslogTarget,此处不再细述, 更重要的是,你可以自定义target类来记录日志

结构分析

Yii2的日志主要由yii\log\Logger,yii\log\Dispatcher,yii\log\Target三类来完成,其中Logger在内存中记录日志信息,当日志信息数达到一定量或者是脚本结束时, Logger就把日志信息交给了Dispatcher, Dispatcher把日志根据不同的配置分发到不同的Target子类,最终Target的子类来完成对日志的具体处理:

yii2-log

代码跟踪

1.Yii类中yii\db\Logger的实例化,,当调用Yii::info('反正我信了')时,Yii类(BaseYii)是如何反应的

代码yii\BaseYii#353:
//私有的静态属性$_logger用来储存Logger对象
private static $_logger; //公有方法返回Logger的单例对象 public static function getLogger() { if (self::$_logger !== null) { return self::$_logger; } else { return self::$_logger = static::createObject('yii\log\Logger'); } } //调用info等写日志方法时,实际调用的是Logger的log方法,并传递了写入的信息$message,日志等级,日志分类$category public static function info($message, $category = 'application') { static::getLogger()->log($message, Logger::LEVEL_INFO, $category); } 

2.yii\log\Logger类的log方法

    代码yii\log\Logger#135
    //将日志信息写入到$this->messages属性中
    public function log($message, $level, $category = 'application') { $time = microtime(true); $traces = []; //如果在应用初始化时配置log组件的traceLevel大于0,则将debug_backtrace信息也记录到日志中 if ($this->traceLevel > 0) { $count = 0; $ts = debug_backtrace(); array_pop($ts); // remove the last trace since it would be the entry script, not very useful foreach ($ts as $trace) { if (isset($trace['file'], $trace['line']) && strpos($trace['file'], YII2_PATH) !== 0) { unset($trace['object'], $trace['args']); $traces[] = $trace; if (++$count >= $this->traceLevel) { break; } } } } //将信息保存到messages数组 $this->messages[] = [$message, $level, $category, $time, $traces]; //当保存的信息数量达到$this->flushInterval属性值时,执行flush方法清空日志,默认值为1000 if ($this->flushInterval > 0 && count($this->messages) >= $this->flushInterval) { $this->flush(); } } //清空日志信息,其实是调用yii\db\Dispatcher的dispatch方法,并传递信息数组$this->messages,和$final参数,$final为true表示脚本已执行结束,不管messages已经多少条都会写入 public function flush($final = false) { if ($this->dispatcher instanceof Dispatcher) { $this->dispatcher->dispatch($this->messages, $final); } $this->messages = []; } 

3.yii\log\Dispatcher类的dispatch方法, 此类即应用的log组件

    代码yii\log\Dispatcher#177
    public $targets = [];    //targets来自于应用的配置,参见代码@app/configs/web.php
    public function dispatch($messages, $final) { $targetErrors = []; //遍历所有的targets,如果target可用(enabled属性为true),执行target的collect方法(collect方法在父类yii\log\Target中实现) foreach ($this->targets as $target) { if ($target->enabled) { try { //调用yii\log\Target的collect方法 $target->collect($messages, $final); } catch (\Exception $e) { $target->enabled = false; $targetErrors[] = [ 'Unable to send log via ' . get_class($target) . ': ' . ErrorHandler::convertExceptionToString($e), Logger::LEVEL_WARNING, __METHOD__, microtime(true), [], ]; } } } if (!empty($targetErrors)) { $this->dispatch($targetErrors, true); } } 
代码@app/configs/web.php
...
'components' => [
        ...
        //此处配置yii\log\Dispatcher的属性
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0, //traceLevel大于0,则会记录debug_backtrace信息 //此处配置yii\log\Dispatcher的targets属性,每个子元素都是yii\log\Target的子类 'targets' => [ [ 'class' => 'yii\log\DbTarget', //DbTaget类表示将日志记录到数据库中 'levels' => ['error', 'warning','info'], 'logVars'=>[], 'logTable'=>'log',//logTable表示要记录日志的表名,默认为log ], ... ], ], ... ], ... 

4.yii\log\Target类的collect方法

    代码yii\log\Target#100
    //执行对$messages的收集
    public function collect($messages, $final) { //对$messages进行过滤,过滤掉不属于当前调用的target的信息 $this->messages = array_merge($this->messages, $this->filterMessages($messages, $this->getLevels(), $this->categories, $this->except)); $count = count($this->messages); //当日志信息数量达到执行数量$this->exportInterval时执行,默认值为1000 if ($count > 0 && ($final || $this->exportInterval > 0 && $count >= $this->exportInterval)) { //记录$_GET,$_POST,$_SERVER等系统访问信息 if (($context = $this->getContextMessage()) !== '') { $this->messages[] = [$context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME]; } // set exportInterval to 0 to avoid triggering export again while exporting $oldExportInterval = $this->exportInterval; $this->exportInterval = 0; //调用export方法,此方法最终实现对message的处理,参见代码yii\log\FileTarget $this->export(); $this->exportInterval = $oldExportInterval; $this->messages = []; } } 

5.以日志写入到文件为例,yii\log\FileTarget类的export方法

    代码yii\log\FileTarget#97
    //将messages写入到文件$this->logFile中
    public function export() { //对messages进行格式化处理 $text = implode("\n", array_map([$this, 'formatMessage'], $this->messages)) . "\n"; if (($fp = @fopen($this->logFile, 'a')) === false) { throw new InvalidConfigException("Unable to append to log file: {$this->logFile}"); } @flock($fp, LOCK_EX); // clear stat cache to ensure getting the real current file size and not a cached one // this may result in rotating twice when cached file size is used on subsequent calls clearstatcache(); if (@filesize($this->logFile) > $this->maxFileSize * 1024) { $this->rotateFiles(); @flock($fp, LOCK_UN); @fclose($fp); //执行写入 @file_put_contents($this->logFile, $text, FILE_APPEND | LOCK_EX); } else { //执行写入 @fwrite($fp, $text); @flock($fp, LOCK_UN); @fclose($fp); } if ($this->fileMode !== null) { @chmod($this->logFile, $this->fileMode); }

转载于:https://www.cnblogs.com/wjq310/p/6375188.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值