À propos de la fonction de journalisation dans le framework Yii de PHP

不言
Libérer: 2023-04-01 13:48:02
original
1946 Les gens l'ont consulté

Cet article présente principalement les logs dans le framework Yii de PHP. L'analyse des logs est la base de la maintenance quotidienne du site Web. Yii fournit une fonction de log relativement puissante. Les amis qui en ont besoin peuvent s'y référer

. Activer les journaux au niveau de la page Yii
Ajouter la section de journal dans Main.php,
afficher le tableau des journaux de page ci-dessous ( 'class'=>'CWebLogRoute', 'levels'=> 'trace ', //Le niveau est trace 'categories'=>'system.db.*' //Afficher uniquement les informations sur la base de données, y compris la connexion à la base de données, l'instruction d'exécution de la base de données),
est la suivante :

'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',
      ),
      */
    ),
  ),
Copier après la connexion

Extension du composant de journal fourni avec Yii2

 <?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 = &#39;&#39;;

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

    // 启用日志前缀
    if ($this->enableDatePrefix) {
      $filename = basename($this->logFile);
      $this->logFile = $this->_logFilePath . &#39;/&#39; . date(&#39;Ymd&#39;) . &#39;_&#39; . $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;
    }

  }
}
Copier après la connexion

Dans le fichier de configuration comme ceci Utilisation :

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

Logique de journal Yii
Yii utilise un mécanisme de traitement de journal hiérarchique, c'est-à-dire que la collecte des journaux et la journalisation Le traitement final (tel que l'affichage, l'enregistrement dans un fichier, l'enregistrement dans les données) est séparé.
La collecte des informations de journal est complétée par CLogger (enregistreur de journal), et la distribution et le traitement des informations de journal sont distribués aux objets de traitement (tels que CFileLogRoute et l'héritage sous le répertoire de journalisation) sous la planification de CLogRouter (appelé journal gestionnaire de routage) (de la classe CLogRoute, appelée processeur de journal), après avoir lu à plusieurs reprises son code source, j'ai été impressionné par les idées de conception de Yii. Un tel traitement en couches facilite une expansion flexible.
Les informations du journal sont divisées en niveaux, tels que les niveaux d'informations ordinaires, de profil, de trace, d'avertissement et d'erreur. Vous pouvez définir des conditions de filtrage dans le routage des journaux, telles que la définition de l'attribut niveaux de CFileRoute pour traiter uniquement les informations du journal du. niveau spécifié.
Si appelé dans un programme :

Yii::log($message,CLogger::LEVEL_ERROR,$category);
Copier après la connexion

Le processus correspondant peut être le suivant :

  • Générer une instance CLogger

  • Si YII_DEBUG et YII_TRACE_LEVEL ont été définis comme valeurs valides et que le niveau de journalisation n'est pas un profil, les informations de traçage des appels seront générées et ajoutées aux informations du journal.

  • Appelez CLogger::log($msg,$level,$category) pour collecter les journaux. En fait, les journaux ne sont pas écrits dans le fichier pour le moment, mais ne le sont que temporairement. stockés dans la mémoire.

Question : Quand le journal a-t-il été écrit dans le fichier ?
Après un suivi répété, j'ai découvert que le processeur CLogRouter::processLogs() est lié à l'événement OnEndRequest de l'objet Application dans la méthode init de la classe CLogRouter. Dans le même temps, la méthode du processeur d'événements CLogRouter::collectLogs est également liée à l'événement onFlush de Yii::$_logger, qui est utilisé pour actualiser le journal et l'écrire dans le fichier en temps opportun lorsqu'il y a trop de journaux. messages dans Yii::log(). Le code est le suivant :

/**
 * 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(&#39;onFlush&#39;,array($this,&#39;collectLogs&#39;)); 
  Yii::app()->attachEventHandler(&#39;onEndRequest&#39;,array($this,&#39;processLogs&#39;));}
Copier après la connexion

Et défini dans la méthode CApplication::run() :

 if($this->hasEventHandler(&#39;onEndRequest&#39;)) {
 $this->onEndRequest(new CEvent($this));
 }
Copier après la connexion

À ce stade, nous pouvons comprendre que CLogger (Yii::$_logger) collecte uniquement les journaux (les enregistre dans la structure de contenu), puis à la fin du programme, $ L'objet application appelle processLogs de CLogRouter pour le traitement des journaux. Yii prend en charge plusieurs routages de journaux. Par exemple, le même journal peut être écrit dans un fichier, affiché sur la page, ou même envoyé par courrier électronique en même temps, ou même enregistré dans la base de données en même temps. le journal dans le fichier de configuration : la configuration des routes est implémentée en configurant plusieurs éléments pour log:routes afin d'obtenir une distribution de plusieurs routes. Le filtrage et l'enregistrement des informations du journal sont traités par le processeur de journal final.
Les tâches à accomplir par le processeur de logs comprennent principalement les points suivants : Obtenir tous les logs de CLogger et les filtrer (principalement les niveaux et catégories définis par log:routes:levels/categories)

Premier pour le filtrage , reportez-vous à la logique dans CFileLogRoute::collectLogs() :

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

Le filtrage du journal est terminé, puis le traitement final du journal ( comme l'écriture dans des fichiers, des enregistrements dans des bases de données, etc.)

 CFileLogRoute::processLogs($logs);
Copier après la connexion

Mais il y a un petit bug dans cette fonction, qui ne fait que déterminer si le répertoire des journaux est disponible Écrivez, sans juger si le fichier journal lui-même est accessible en écriture. CFileLogRoute implémente une fonction de rotation des journaux (LogRoate) similaire à Linux et stipule la taille du fichier journal. C'est très réfléchi et parfait ! pour en tirer des leçons et s'imprégner de ses idées !
Configuration dans protected/config/main.php :

&#39;preload&#39;=>array(&#39;log&#39;),
components => array(
       &#39;log&#39;=>array(
         &#39;class&#39;=>&#39;CLogRouter&#39;,
         &#39;routes&#39;=>array(
          array(
            &#39;class&#39;=>&#39;CFileLogRoute&#39;,
            &#39;levels&#39;=>&#39;error, warning,trace&#39;,
          ),
         )
        )
       )
Copier après la connexion

定义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(&#39;onEndRequest&#39;)) {
  $this->onEndRequest(new CEvent($this));
 }
Copier après la connexion

也就是说,日志的最终处理(比如写入文件,系统日志,发送邮件)是发生在应用程序运行完毕之后的。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组件添加新的路由配置:

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

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

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

Yii2框架实现数据库常用操作解析

关于yii2中结合gridview使用modal弹窗的代码

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal