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' =>
'password' => 'you password',
'timeout' => 30,
'emails' =>
'[email protected],[email protected]', #日誌接收人。
'sentfrom' => '
),
經過以上處理,即可使之實現我們的目的,當然你可以根據自己的需要進一步擴充套件之。
Yii的日誌的處理機制以及擴充套件案例
yii使用層次的日誌處理機制,即日誌的收集與日誌最終的處理 如顯示 儲存到檔案 儲存到資料數 是分離的。日誌資訊的收集由clogger 日誌記錄器 完成,而日誌資訊的分發處理,則在clogrouter的排程 稱為日誌路由管理器 下,分發給處理物件 如cfilelogroute以及logging目錄下...
C 的事件處理機制
在以往的關於事件處理的程式中,我們更多的是採用一種迴圈等待的方式,即為了檢測某個事件是否發生,迴圈的檢測某個變數是否發生變化但這樣會占用大量的資源。而c 的事件處理機制提供了一種非常好的解決方案。程式不再不停的檢查裝置,而是等待訊息的到來,然後交給程式來處理他它。這樣的話,作業系統中只是傻瓜式的將訊...
Python的異常處理機制
當你的程式中出現異常情況時就需要異常處理。比如當你開啟乙個不存在的檔案時。當你的程式中有一些無效的語句時,python會提示你有錯誤存在。下面是乙個拼寫錯誤的例子,print寫成了print。python是大小寫敏感的,因此python將引發乙個錯誤 print hello world file l...