文档章节

Yii2的log分析

雁子久久
 雁子久久
发布于 2014/12/08 16:10
字数 2187
阅读 1111
收藏 7

体验yii2的log功能

  1. 创建一个yii2的应用
  2. 在@app/Controllers目录新建一个TestController, 在控制器里新建一个actionIndex方法
class TestController extends Controller{
    public function actionIndex() {
        
    }
}

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

  1. 在actionIndex方法中写日志
...
public function actionIndex() {
       //记录一个错误级别的日志
       Yii::error('人艰不拆!');
   }
...
  1. 进入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
  1. 提示级别 INFO
//记录一个提示级别的日志
Yii::info('喝酸奶只舔盖,我就是这么任性!');
  1. 代码追踪级别 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',
                ],
            ],
        ],
        ...
    ],
...
  1. 调用的时候,只需要加上第二个参数,填写对应的分类即可
public function actionIndex() {
        //日志的第二个参数就是分类category
        Yii::info('select * from table', 'yii\db\Query');
}
  1. 进入@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
                ],
                ...
            ],
        ],
        ...
    ],
...
  1. 此时当你再次使用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,记录到syslog yii\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);
        }
    }

© 著作权归作者所有

共有 人打赏支持
上一篇: 前篇
下一篇: Yii视频下载地址
雁子久久
粉丝 21
博文 26
码字总数 17771
作品 0
昌平
私信 提问
加载中

评论(2)

顺顺利利
顺顺利利
必须顶一个,真是帮了我一个大忙啊,刚开始研究YII
咚往咚来
咚往咚来
79
Yii2 模块化调用Module失败

一、错误信息如下: Unknown Class – yii\base\UnknownClassException Unable to find 'app\modules\user\UserModule' in file: E:\www\test\basic/modules/user/UserModule.php. Namespac......

joson_chan
2015/09/23
4.3K
1
Yii 2 —— 密码加密算法

1.1 密码加密算法 参考文档: 1、更新后的 PHP: 现代 PHP 中的密码安全性; 2、http://php.net/manual/zh/function.password-hash.php 3、http://php.net/manual/zh/function.password-veri......

tywali
2018/06/29
0
0
yii2源码分析之执行基本流程

用yii2框架用了将近2年,一直都没有去看过它底层源码, 马上快不用了,最近对其源码研究一番,哈哈 废话少说,上代码, 入口文件是web/index.php

china_lx1
2018/04/22
0
0
Yii 2.0.2 发布

Yii 2.0.2 发布,此版本现已提供下载:https://github.com/yiisoft/yii2/releases/tag/2.0.2。 Yii 2.0.2 是 Yii 2.0 的分支,包括大约 40 个新特性和 bug 修复,完整的更新列表请看change ...

oschina
2015/01/12
4.4K
30
安装使用yii-debug-toolbar,yii框架的调试插件

从github下载yii-debug-toolbar源码:https://github.com/malyshev/yii-debug-toolbar/downloads 2. 假设yii的项目创建在了/export/dev/yii-demo 将下载的文件解压缩到/export/dev/yii-demo/......

李佳顺
2014/04/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【机器学习PAI实战】—— 玩转人工智能之商品价格预测

摘要: 我们经常思考机器学习,深度学习,以至于人工智能给我们带来什么?在数据相对充足,足够真实的情况下,好的学习模型可以发现事件本身的内在规则,内在联系。我们去除冗余的信息,可以...

zhaowei121
9分钟前
0
0
Spring拓展接口之FactoryBean,我们来看看其源码实现

是什么 FactoryBean的源码比较简单,大家可以细读下其注释,我做了简单的如下翻译 /** * 实现此接口的bean不能用作普通bean。此bean暴露的对象是通过getObject()创建的对象,而不是它自身...

java菜分享
13分钟前
1
0
Pod在多可用区worker节点上的高可用部署

一、 需求分析 当前kubernetes集群中的worker节点可以支持添加多可用区中的ECS,这种部署方式的目的是可以让一个应用的多个pod(至少两个)能够分布在不同的可用区,起码不能分布在同一个可用...

阿里云官方博客
19分钟前
0
0
深入理解 Hive 分区分桶 (Inceptor)

分区是hive存放数据的一种方式。将列值作为目录来存放数据,就是一个分区。这样查询时使用分区列进行过滤,只需根据列值直接扫描对应目录下的数据,不扫描其他不关心的分区,快速定位,提高查...

hblt-j
27分钟前
0
0
数据结构

什么是数据结构 1、数据 数据是描述客观世界的数字、字符以及一切能够输入到计算机中,并且能够被计算机程序处理的符号集合。简言之,数据就是计算机加工处理的原料,是信息的载体。 2、数据...

stars永恒
37分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部