Yii的日誌的處理機制以及擴充套件案例

2021-07-09 07:41:37 字數 4226 閱讀 8448

yii使用層次的日誌處理機制,即日誌的收集與日誌最終的處理(如顯示、儲存到檔案、儲存到資料數)是分離的。

日誌資訊的收集由clogger(日誌記錄器)完成,而日誌資訊的分發處理,則在clogrouter的排程(稱為日誌路由管理器)下,分發給處理物件(如cfilelogroute以及logging目錄下繼承自clogroute的類, 稱為日誌處理器),經過反覆閱讀其源**,我更是為yii的設計思想所折服,如此的分層處理,使得其易於靈活擴充套件。

而日誌資訊有級別之分,如普通的info, profile, trace, warning, error級別,可以在日誌路由中設定過慮條件,如設定cfileroute的levels屬性,即可只處理指定級別的日誌資訊。

如在程式中呼叫:

yii::log($message,clogger::level_error,$category);

對應的流程可能如下:

1. 生成clogger例項

2. 如果yii_debug , yii_trace_level都已經定義為有效值,並且日誌級別不是profile, 則產生呼叫回溯資訊, 並追加到日誌資訊上。

3. 呼叫clogger::

log($msg,$level,$category)

收集日誌,實際上這時日誌並沒有寫入檔案,僅僅是暫存於記憶體之中。

問題:日誌是在何時被寫入檔案的?

同時也給yii::$_logger的onflush事件繫結事件處理器clogrouter::collectlogs方法,用於在yii::log()中當日誌訊息量過多時,及時將日誌重新整理寫入檔案。

if($this->haseventhandler('onendrequest')) 

日誌處理器要完成的任務主要包含以下幾點:

從clogger中取得所有日誌,並進行過濾(主要是levels, categories兩項定義log:routes:levels/categories)

1. 先進行過濾

參考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屬性)及其配置屬性。

建立並初始化乙個元件時,實際上呼叫的是cmodule::getcomponent, 這個呼叫中使用yiibase::createcomponent建立元件物件,並再呼叫元件的init初始化之。

if($this->haseventhandler('onendrequest')) 

也就是說,日誌的最終處理(比如寫入檔案,系統日誌,傳送郵件)是發生在應用程式執行完畢之後的。yii使用事件機制,巧妙地實現了事件與處理控制代碼的關聯。

也就是說,當應用程式執行完畢,將執行clogrouter::processlogs,對日誌進行處理,。clogrouter被稱之為日誌路由管理器。每個日誌路由處理器從clooger物件中取得相應的日誌(使用過濾機制),作最終處理。

具體而言yii的日誌系統,分為以下幾個層次:

日誌傳送者,即程式中呼叫yii::log($msg, $level, $category),將日誌傳送給clogger物件

clogger物件負責將日誌記錄暫存於記憶體之中

程式執行結束後,log元件(日誌路由管理器clogroute)的processlogs方法被啟用執行,由其逐個呼叫日誌路由器,作日誌的最後處理。

大致過程如下:

2. 3. 

應用程式的其它部分通過呼叫yii::log()向clogger元件傳送日誌資訊,clogger元件將日誌資訊暫存到記憶體中。

4. yii的日誌路由機制,給日誌系統擴充套件帶來了無限的靈活。並且其多道路由處理機制,可將同乙份日誌資訊進行多種方式處理。

這裡舉出乙個案例:發生error級別的資料庫錯誤時,及時給相關維護人員傳送電子郵件,並同時將這些日誌記錄到檔案之中。

規劃思路,傳送郵件和手機簡訊是兩個不同的功能,yii已經帶了日誌郵件傳送元件(logging/cemaillogroute.php),但這個元件中卻使用了php自帶的mail函式,使用mail函式需要配置php.ini中的smtp主機,並且使用非驗證傳送方式,這種方式在目前的實際情況下已經完全不可使用。代替地我們需要使用帶驗證功能的smtp傳送方式。

1. 在protected/components/目錄下定義日誌處理器類myemaillogroute,並讓其繼承自cemaillogroute,最主要的目的是重寫cemaillogroute::sendemail()方法

protected/components/myemaillogroute.php的內容

<?php

class myemaillogroute extends cemaillogroute 

}

public function setactive($setactive=false) 

}

public function connect($reconnect = false) 

}yii::trace("conneted to smtp server $host:$port");

return true ;

}

#use $this->user, $this->password to login smtp server.

private function login() 

public function sendemail($email,$subject,$message) 

public function _sendemail($receiver, $subject, $message) 

}

其中,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' => 

'[email protected]',

'password' => 'you password',

'timeout' => 30,

'emails' => 

'[email protected],[email protected]', #日誌接收人。

'sentfrom' => '

[email protected]',

),

經過以上處理,即可使之實現我們的目的,當然你可以根據自己的需要進一步擴充套件之。

Yii的日誌的處理機制以及擴充套件案例

yii使用層次的日誌處理機制,即日誌的收集與日誌最終的處理 如顯示 儲存到檔案 儲存到資料數 是分離的。日誌資訊的收集由clogger 日誌記錄器 完成,而日誌資訊的分發處理,則在clogrouter的排程 稱為日誌路由管理器 下,分發給處理物件 如cfilelogroute以及logging目錄下...

C 的事件處理機制

在以往的關於事件處理的程式中,我們更多的是採用一種迴圈等待的方式,即為了檢測某個事件是否發生,迴圈的檢測某個變數是否發生變化但這樣會占用大量的資源。而c 的事件處理機制提供了一種非常好的解決方案。程式不再不停的檢查裝置,而是等待訊息的到來,然後交給程式來處理他它。這樣的話,作業系統中只是傻瓜式的將訊...

Python的異常處理機制

當你的程式中出現異常情況時就需要異常處理。比如當你開啟乙個不存在的檔案時。當你的程式中有一些無效的語句時,python會提示你有錯誤存在。下面是乙個拼寫錯誤的例子,print寫成了print。python是大小寫敏感的,因此python將引發乙個錯誤 print hello world file l...