• 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' => 'yiilogFileTarget',
                       'levels' => ['error', 'warning','info','trace','profile'],
                       'logVars'=>[],
                       //除了except对应的分类之外,其他的都写入到
                       'except'=>['yiidb*','appmodels*']
                   ],
                   //在原配置的基础上,增加以下配置(新增一个target)
                    [
                       'class' => 'yiilogFileTarget',
                       'levels' => ['error', 'warning','info','trace','profile'],
                       'logVars'=>[],
                       //表示以yiidb或者appmodels开头的分类都会写入这个文件
                       'categories'=>['yiidb*','appmodels*'],
                       //表示写入到文件sql.log中
                       'logFile'=>'@runtime/logs/sql.log',
                   ],
               ],
           ],
           ...
       ],
      ...
      
    2. 调用的时候,只需要加上第二个参数,填写对应的分类即可

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

      └── logs
       ├── app.log
       └── sql.log
      //sql.log内容如下
      2014-12-05 18:58:51 [10.18.60.111][-][-][info][yiidbQuery] 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' => 'yiilogFileTarget',
                       'levels' => ['error', 'warning','info','trace','profile'],
                       'logVars'=>[],
                       //表示以yiidb或者appmodels开头的分类都会写入这个文件
                       'categories'=>['yiidb*','appmodels*'],
                       //表示写入到文件sql.log.2014xxxx
                       'logFile'=>'@runtime/logs/sql.log.'.date('Ymd'),
                   ],
               ],
           ],
           ...
       ],
      ...
      
      2.再次使用Yii::info('select * from table', 'yiidbQuery');, 你会看到日志目录里
      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' => 'yiilogDbTarget',  //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除了支持记录到文件和数据库,还可以直接发送邮件yiilogEmailTarget,记录到syslogyiilogSyslogTarget,此处不再细述, 更重要的是,你可以自定义target类来记录日志

    结构分析

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

    yii2-log

    代码跟踪

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

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

    2.yiilogLogger类的log方法

        代码yiilogLogger#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();
            }
        }
        //清空日志信息,其实是调用yiidbDispatcher的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.yiilogDispatcher类的dispatch方法, 此类即应用的log组件

        代码yiilogDispatcher#177
        public $targets = [];    //targets来自于应用的配置,参见代码@app/configs/web.php
        public function dispatch($messages, $final)
        {
            $targetErrors = [];
            //遍历所有的targets,如果target可用(enabled属性为true),执行target的collect方法(collect方法在父类yiilogTarget中实现)
            foreach ($this->targets as $target) {
                if ($target->enabled) {
                    try {
                        //调用yiilogTarget的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' => [
            ...
            //此处配置yiilogDispatcher的属性
            'log' => [
                'traceLevel' => YII_DEBUG ? 3 : 0,    //traceLevel大于0,则会记录debug_backtrace信息
                //此处配置yiilogDispatcher的targets属性,每个子元素都是yiilogTarget的子类
                'targets' => [
                    [
                        'class' => 'yiilogDbTarget',  //DbTaget类表示将日志记录到数据库中
                        'levels' => ['error', 'warning','info'],
                        'logVars'=>[],
                        'logTable'=>'log',//logTable表示要记录日志的表名,默认为log
                    ],
                    ...
                ],
            ],
            ...
        ],
    ...
    

    4.yiilogTarget类的collect方法

        代码yiilogTarget#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的处理,参见代码yiilogFileTarget
                $this->export();
                $this->exportInterval = $oldExportInterval;
    
                $this->messages = [];
            }
        }
    

    5.以日志写入到文件为例,yiilogFileTarget类的export方法

        代码yiilogFileTarget#97
        //将messages写入到文件$this->logFile中
        public function export()
        {
            //对messages进行格式化处理
            $text = implode("
    ", array_map([$this, 'formatMessage'], $this->messages)) . "
    ";
            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);
            }
  • 相关阅读:
    JQuery 快速入门一篇通
    Winform 显示Gif图片
    MD5编码工具类 MD5Code.java
    Asp.Net 上传图片并生成高清晰缩略图
    winform时钟c#代码
    PHP面试题汇总
    PHP条件语句语法与示例
    Android声音播放实例代码
    html和js基础功能代码备份
    纯C#实现屏幕指定区域截屏
  • 原文地址:https://www.cnblogs.com/wjq310/p/6375188.html
Copyright © 2020-2023  润新知