search
Homephp教程php手册全面解读PHP的Yii框架中的日志功能
全面解读PHP的Yii框架中的日志功能Jun 06, 2016 pm 07:32 PM
phpyiicomprehensiveFunctionlogframeInterpretation

Yii页面级日志开启 在 Main.php中 log段添加、 下面显示页面日志 array( 'class'='CWebLogRoute', 'levels'='trace', //级别为trace 'categories'='system.db.*' //只显示关于数据库信息,包括数据库连接,数据库执行语句 ), 完整如下: 'log'=array( 'class'=

Yii页面级日志开启
在 Main.php中 log段添加、
下面显示页面日志 array( 'class'=>'CWebLogRoute', 'levels'=>'trace', //级别为trace 'categories'=>'system.db.*' //只显示关于数据库信息,包括数据库连接,数据库执行语句 ),
完整如下:

'log'=>array(
    'class'=>'CLogRouter',
    'routes'=>array(
      array(
        'class'=>'CFileLogRoute',
        'levels'=>'error, warning',

      ),
              // 下面显示页面日志 
              array( 
               'class'=>'CWebLogRoute', 
               'levels'=>'trace',  //级别为trace 
               'categories'=>'system.db.*' //只显示关于数据库信息,包括数据库连接,数据库执行语句 
              ), 
      // uncomment the following to show log messages on web pages
      /*
      array(
        'class'=>'CWebLogRoute',
      ),
      */
    ),
  ),

    
扩展 Yii2 自带的日志组件
   

 <&#63;php

/**
 * author   : forecho <caizhenghai@gmail.com>
 * createTime : 2015/12/22 18:13
 * description:
 */
namespace common\components;

use Yii;
use yii\helpers\FileHelper;

class FileTarget extends \yii\log\FileTarget
{
  /**
   * @var bool 是否启用日志前缀 (@app/runtime/logs/error/20151223_app.log)
   */
  public $enableDatePrefix = false;

  /**
   * @var bool 启用日志等级目录
   */
  public $enableCategoryDir = false;

  private $_logFilePath = '';

  public function init()
  {
    if ($this->logFile === null) {
      $this->logFile = Yii::$app->getRuntimePath() . '/logs/app.log';
    } else {
      $this->logFile = Yii::getAlias($this->logFile);
    }
    $this->_logFilePath = dirname($this->logFile);

    // 启用日志前缀
    if ($this->enableDatePrefix) {
      $filename = basename($this->logFile);
      $this->logFile = $this->_logFilePath . '/' . date('Ymd') . '_' . $filename;
    }

    if (!is_dir($this->_logFilePath)) {
      FileHelper::createDirectory($this->_logFilePath, $this->dirMode, true);
    }

    if ($this->maxLogFiles < 1) {
      $this->maxLogFiles = 1;
    }
    if ($this->maxFileSize < 1) {
      $this->maxFileSize = 1;
    }

  }
}

在配置文件中这样使用:

'components' => [
  'log' => [
    'traceLevel' => YII_DEBUG &#63; 3 : 0,
    'targets' => [
      /**
       * 错误级别日志:当某些需要立马解决的致命问题发生的时候,调用此方法记录相关信息。
       * 使用方法:Yii::error()
       */
      [
        'class' => 'common\components\FileTarget',
        // 日志等级
        'levels' => ['error'],
        // 被收集记录的额外数据
        'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
        // 指定日志保存的文件名
        'logFile' => '@app/runtime/logs/error/app.log',
        // 是否开启日志 (@app/runtime/logs/error/20151223_app.log)
        'enableDatePrefix' => true,
        'maxFileSize' => 1024 * 1,
        'maxLogFiles' => 100,
      ],
      /**
       * 警告级别日志:当某些期望之外的事情发生的时候,使用该方法。
       * 使用方法:Yii::warning()
       */
      [
        'class' => 'common\components\FileTarget',
        // 日志等级
        'levels' => ['warning'],
        // 被收集记录的额外数据
        'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
        // 指定日志保存的文件名
        'logFile' => '@app/runtime/logs/warning/app.log',
        // 是否开启日志 (@app/runtime/logs/warning/20151223_app.log)
        'enableDatePrefix' => true,
        'maxFileSize' => 1024 * 1,
        'maxLogFiles' => 100,
      ],
      /**
       * info 级别日志:在某些位置记录一些比较有用的信息的时候使用。
       * 使用方法:Yii::info()
       */
      [
        'class' => 'common\components\FileTarget',
        // 日志等级
        'levels' => ['info'],
        // 被收集记录的额外数据
        'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
        // 指定日志保存的文件名
        'logFile' => '@app/runtime/logs/info/app.log',
        // 是否开启日志 (@app/runtime/logs/info/20151223_app.log)
        'enableDatePrefix' => true,
        'maxFileSize' => 1024 * 1,
        'maxLogFiles' => 100,
      ],
      /**
       * trace 级别日志:记录关于某段代码运行的相关消息。主要是用于开发环境。
       * 使用方法:Yii::trace()
       */
      [
        'class' => 'common\components\FileTarget',
        // 日志等级
        'levels' => ['trace'],
        // 被收集记录的额外数据
        'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION','_SERVER'],
        // 指定日志保存的文件名
        'logFile' => '@app/runtime/logs/trace/app.log',
        // 是否开启日志 (@app/runtime/logs/trace/20151223_app.log)
        'enableDatePrefix' => true,
        'maxFileSize' => 1024 * 1,
        'maxLogFiles' => 100,
      ],
    ],
  ],
],

yii日志的逻辑
Yii使用层次的日志处理机制,即日志的收集与日志最终的处理(如显示、保存到文件、保存到数据数)是分离的。
日志信息的收集由CLogger(日志记录器)完成,而日志信息的分发处理,则在CLogRouter的调度(称为日志路由管理器)下,分发给处理对象(如CFileLogRoute以及logging目录下继承自CLogRoute的类, 称为日志处理器),经过反复阅读其源代码,我更是为Yii的设计思想所折服,如此的分层处理,使得其易于灵活扩展。
而日志信息有级别之分,如普通的info, profile, trace, warning, error级别,可以在日志路由中设置过虑条件,如设置CFileRoute的levels属性,即可只处理指定级别的日志信息。
如在程序中调用:

Yii::log($message,CLogger::LEVEL_ERROR,$category);

对应的流程可能如下:

  • 生成CLogger实例
  • 如果YII_DEBUG , YII_TRACE_LEVEL都已经定义为有效值,并且日志级别不是profile, 则产生调用回溯信息, 并追加到日志信息上。
  • 调用CLogger:: log($msg,$level,$category) 收集日志,实际上这时日志并没有写入文件,仅仅是暂存于内存之中。

问题:日志是在何时被写入文件的?
经过反复跟踪,我发现在CLogRouter类的init方法中为Application对象的OnEndRequest事件绑定处理器CLogRouter::processLogs()。同时也给Yii::$_logger的onFlush事件绑定事件处理器CLogRouter::collectLogs方法,用于在Yii::log()中当日志消息量过多时,及时将日志刷新写入文件。代码如下:

/**
 * Initializes this application component.
 * This method is required by the IApplicationComponent interface.  
*/
 public function init(){ 
  parent::init(); 
  foreach($this->_routes as $name=>$route) { 
    $route=Yii::createComponent($route);  
    $route->init();  
    $this->_routes[$name]=$route; 
  } 
  Yii::getLogger()->attachEventHandler('onFlush',array($this,'collectLogs')); 
  Yii::app()->attachEventHandler('onEndRequest',array($this,'processLogs'));}

而在CApplication::run()方法中定义了:

 if($this->hasEventHandler('onEndRequest')) {
 $this->onEndRequest(new CEvent($this));
 }

到这里我们可以理解CLogger (Yii::$_logger)仅仅是将日志进行收集(记录到内容结构之中),然后在程序结束时,由$app对象调用CLogRouter的processLogs进行日志的处理。Yii支持日志多道路由,比如:同一份日志即可写入至文件,又可显示到页面上,甚至同时以电子邮件发送,更甚至同时记录到数据库中,这是由配置文件中的log:routes配置实现的,为log:routes配置多个元素,实现多个路由分发。日志信息的过滤,记录均是由最终的日志处理器处理。
日志处理器要完成的任务主要包含以下几点: 从CLogger中取得所有日志,并进行过滤(主要是levels, categories两项定义log:routes:levels/categories)

先进行过滤参考CFileLogRoute::collectLogs()中的逻辑:

 $logs=$logger->getLogs($this->levels,$this->categories); //执行过滤,只得到期望信息

日志过滤已经完成接下来就要对日志进行最终处理(如写入到文件,记录至数据库等)

 CFileLogRoute::processLogs($logs);

但这个函数之中,有个小bug, 只判断日志目录是否可写,没有判断日志文件本身是否可写.CFileLogRoute实现了类似Linux的日志轮换功能(LogRoate), 并规定了日志文件的大小,考虑得很周到,很完善! 我也要向其学习并吸收其思想!
protected/config/main.php中的配置:

'preload'=>array('log'),
components => array(
       'log'=>array(
         'class'=>'CLogRouter',
         'routes'=>array(
          array(
            'class'=>'CFileLogRoute',
            'levels'=>'error, warning,trace',
          ),
         )
        )
       )

定义log组件需要预先加载(实例化)。配置使用CLogRouter作为日志路由管理器,并设置了其日志路由处理器(routes属性)及其配置属性。而preload, log属性的定义,均要应用到CWebApplication对象上(请参阅CApplication::__construct中的configure调用, configure从CModule继承而来)。而在CWebApplication的构造函数中执行preloadComponents(),就创建了log对象(即CLogRouter的实例)。
创建并初始化一个组件时,实际上调用的是CModule::getComponent, 这个调用中使用YiiBase::createComponent创建组件对象,并再调用组件的init初始化之。
再阅读CLogRouter::init()过程,在这里有两个关键之处,一是创建日志路由处理器(即决定日志的最终处理方式:写入文件,邮件发送等等),二是给应用程序对象绑定onEndRequest事件处理CLogRouter::processLogs()。而在CApplication::run()确实有相关代码用于运行onEndRequest事件处理句柄:

 if($this->hasEventHandler('onEndRequest')) {
  $this->onEndRequest(new CEvent($this));
 }

也就是说,日志的最终处理(比如写入文件,系统日志,发送邮件)是发生在应用程序运行完毕之后的。Yii使用事件机制,巧妙地实现了事件与处理句柄的关联。
也就是说,当应用程序运行完毕,将执行CLogRouter::processLogs,对日志进行处理,。CLogRouter被称之为日志路由管理器。每个日志路由处理器从CLooger对象中取得相应的日志(使用过滤机制),作最终处理。
具体而言Yii的日志系统,分为以下几个层次:

日志发送者,即程序中调用Yii::log($msg, $level, $category),将日志发送给CLogger对象
CLogger对象负责将日志记录暂存于内存之中程序运行结束后,log组件(日志路由管理器CLogRoute)的processLogs方法被激活执行,由其逐个调用日志路由器,作日志的最后处理。

更为详细的大致过程如下:

  • CApplication::__construct()中调用preloadComponents, 这导致log组件(CLogRoute)被实例化,并被调用init方法初始化。
  • log组件(CLogRoute)的init方法中,其是初始化日志路由,并给CApplication对象onEndRequest事件绑定处理流程processLogs。给CLooger组件的onFlush事件绑定处理流程collectLogs。
  • 应用程序的其它部分通过调用Yii::log()向CLogger组件发送日志信息,CLogger组件将日志信息暂存到内存中。
  • CApplication执行完毕(run方法中),会激活onEndRequest事件,绑定的事件处理器processLogs被执行,日志被写入文件之中。 Yii的日志路由机制,给日志系统扩展带来了无限的灵活。并且其多道路由处理机制,可将同一份日志信息进行多种方式处理。

这里举出一个案例:发生error级别的数据库错误时,及时给相关维护人员发送电子邮件,并同时将这些日志记录到文件之中。规划思路,发送邮件和手机短信是两个不同的功能,Yii已经带了日志邮件发送组件(logging/CEmailLogRoute.php),但这个组件中却使用了php自带的mail函数,使用mail函数需要配置php.ini中的smtp主机,并且使用非验证发送方式,这种方式在目前的实际情况下已经完全不可使用。代替地我们需要使用带验证功能的smtp发送方式。在protected/components/目录下定义日志处理器类myEmailLogRoute,并让其继承自CEmailLogRoute,最主要的目的是重写CEmailLogRoute::sendEmail()方法  ,其中,SMTP的处理细节请自行完善(本文的重点是放在如何处理日志上,而不是发送邮件上)。
接下来,我们就可以定义日志路由处理,编辑protected/config/main.php, 在log组件的routes组件添加新的路由配置:

'log'=>array(
'class'=>'CLogRouter',
'routes'=>array(
array(
'class'=>'CFileLogRoute',
'levels'=>'error, warning,trace',
),
array(
'class' => 'myEmailLogRoute',
'levels' => 'error', #所有异常的错误级别均为error, 
'categories' => 'exception.CDbException', #数据库产生错误时,均会产生CDbException异常。
'host' => 'mail.163.com',
'port' => 25,
'user' => 'jeff_yu',
'password' => 'you password',
'timeout' => 30,
'emails' => 'jeff_yu@gmail.com', #日志接收人。
'sentFrom' => 'jeff_yu@gmail.com',
),

经过以上处理,即可使之实现我们的目的,当然你可以根据自己的需要进一步扩展之。

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

Win11系统下如何显示文件后缀?详细解读Win11系统下如何显示文件后缀?详细解读Mar 09, 2024 am 08:24 AM

Win11系统下如何显示文件后缀?详细解读在Windows11操作系统中,文件后缀是指文件名后面的点及其后面的字符,用来表示文件的类型。在默认情况下,Windows11系统会隐藏文件的后缀,这样在文件资源管理器中只能看到文件的名称而无法直观地了解文件的类型。然而,对于一些用户来说,显示文件后缀是非常必要的,因为它能帮助他们更好地辨识文件类型以及进行相关操

电脑中的cookie数据在哪个文件夹?详细解读电脑中的cookie数据在哪个文件夹?详细解读Jan 19, 2024 am 10:19 AM

随着互联网的不断发展,人们越来越离不开浏览器。而在浏览器中,大家都会或多或少用到cookie这个东西。然而,很多人并不知道cookie数据在哪个文件夹中,今天就来详细解读一下。首先,我们需要了解cookie是什么。简单来说,cookie是由浏览器存储的一段文本信息,用于保存用户在浏览器中的一些个人设置或者记录用户的历史操作等等。当用户再次打开同一个网站时,c

php怎么判断有没有小数点php怎么判断有没有小数点Apr 20, 2022 pm 08:12 PM

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

php怎么设置implode没有分隔符php怎么设置implode没有分隔符Apr 18, 2022 pm 05:39 PM

在PHP中,可以利用implode()函数的第一个参数来设置没有分隔符,该函数的第一个参数用于规定数组元素之间放置的内容,默认是空字符串,也可将第一个参数设置为空,语法为“implode(数组)”或者“implode("",数组)”。

php怎么去除首位数字php怎么去除首位数字Apr 20, 2022 pm 03:23 PM

去除方法:1、使用substr_replace()函数将首位数字替换为空字符串即可,语法“substr_replace($num,"",0,1)”;2、用substr截取从第二位数字开始的全部字符即可,语法“substr($num,1)”。

Linux Bashrc是什么?详细解读Linux Bashrc是什么?详细解读Mar 20, 2024 pm 09:18 PM

LinuxBashrc是Linux系统中的一个配置文件,用于设置用户的Bash(BourneAgainShell)环境。Bashrc文件存储了用户登录时所需的环境变量、启动脚本等信息,可以定制化用户的Shell环境。在Linux系统中,每个用户都有一个对应的Bashrc文件,位于用户的家目录下的隐藏文件夹中。Bashrc文件的作用主要有以下几点:设置环

Java文档解读:System类的exit()方法用法解析Java文档解读:System类的exit()方法用法解析Nov 03, 2023 pm 03:27 PM

Java文档解读:System类的exit()方法用法解析,需要具体代码示例System类是Java中的一个重要类,它提供了许多与系统相关的功能和方法。其中,exit()方法是System类中的一个常用方法,用于终止当前正在运行的Java虚拟机。在本文中,我们将对exit()方法的用法进行解析,并给出具体的代码示例。exit()方法的定义如下:public

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

Repo: How To Revive Teammates
1 months agoBy尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
1 months agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor