鍍金池/ 教程/ PHP/ 日志
查詢構(gòu)建器
HTTP 緩存
單元測試
資源
數(shù)據(jù)庫遷移
Fixtures
收集列表輸入
認證
助手類
緩存
數(shù)據(jù)緩存
最佳安全實踐
響應格式
使用 Gii 生成代碼
服務定位器
性能優(yōu)化
資源
多模型的復合表單
控制器
Html 幫助類
運行機制概述
快速入門
屬性(Property)
使用表單
配置測試環(huán)境
數(shù)據(jù)提供者
使用數(shù)據(jù)庫
授權(quán)
輸入驗證
類自動加載(Autoloading)
版本
響應
Sessions 和 Cookies
數(shù)組助手類
創(chuàng)建你自己的應用程序結(jié)構(gòu)
文件上傳
路由
收發(fā)郵件
模型
小部件
更上一層樓
頁面緩存
請求
片段緩存
排序
處理密碼
數(shù)據(jù)小部件
模塊
事件
控制器
從 Yii 1.1 升級
應用組件
驗收測試
入口腳本
總覽
Url 幫助類
行為
速率限制
控制臺命令
依賴注入容器
視圖
功能測試
錯誤處理
過濾器
主題
應用主體
引入第三方代碼
共享托管環(huán)境
測試
擴展
路由
使用模板引擎
核心驗證器(Core Validators)
分頁
數(shù)據(jù)庫訪問 (DAO)
配置
創(chuàng)建表單
日志
安裝 Yii
客戶端腳本使用
組件(Component)
說聲 Hello
運行應用
數(shù)據(jù)格式器
認證
錯誤處理
別名(Aliases)
Active Record
啟動引導(Bootstrapping)
國際化

日志

Yii 提供了一個強大的日志框架,這個框架具有高度的可定制性和可擴展性。使用這個框架,你可以輕松地記錄各種類型的消息,過濾它們,并且將它們收集到不同的目標,諸如文件,數(shù)據(jù)庫,郵件。

使用 Yii 日志框架涉及下面的幾個步驟:

  • 在你代碼里的各個地方記錄 log messages;
  • 在應用配置里通過配置 log targets 來過濾和導出日志消息;
  • 檢查由不同的目標導出的已過濾的日志消息(例如:Yii debugger)。

在這部分,我們主要描述前兩個步驟。

日志消息

記錄日志消息就跟調(diào)用下面的日志方法一樣簡單:

  • [[Yii::trace()]]:記錄一條消息去跟蹤一段代碼是怎樣運行的。這主要在開發(fā)的時候使用。
  • [[Yii::info()]]:記錄一條消息來傳達一些有用的信息。
  • [[Yii::warning()]]:記錄一個警告消息用來指示一些已經(jīng)發(fā)生的意外。
  • [[Yii::error()]]:記錄一個致命的錯誤,這個錯誤應該盡快被檢查。

這些日志記錄方法針對 嚴重程度類別 來記錄日志消息。它們共享相同的函數(shù)簽名 function ($message, $category = 'application'),$message代表要被記錄的日志消息,而 $category 是日志消息的類別。在下面的示例代碼中,在默認的類別 application 下記錄了一條跟蹤消息:

Yii::trace('start calculating average revenue');

信息:日志消息可以是字符串,也可以是復雜的數(shù)據(jù),諸如數(shù)組或者對象。log targets 的義務是正確處理日志消息。默認情況下,假如一條日志消息不是一個字符串,它將被導出為一個字符串,通過調(diào)用 [[yii\helpers\VarDumper::export()]]。

為了更好地組織和過濾日志消息,我們建議您為每個日志消息指定一個適當?shù)念悇e。您可以為類別選擇一個分層命名方案,這將使得 log targets 在基于它們的分類來過濾消息變得更加容易。一個簡單而高效的命名方案是使用 PHP 魔術(shù)常量 __METHOD__ 作為分類名稱。這種方式也在 Yii 框架的核心代碼中得到應用,例如,

Yii::trace('start calculating average revenue', __METHOD__);

__METHOD__ 常量計算值作為該常量出現(xiàn)的地方的方法名(完全限定的類名前綴)。例如,假如上面那行代碼在這個方法內(nèi)被調(diào)用,則它將等于字符串'app\controllers\RevenueController::calculate'。

信息:上面所描述的日志方法實際上是 [[yii\log\Logger|logger object]] 對象(一個通過表達式 Yii::getLogger() 可訪問的單例)的方法 [[yii\log\Logger::log()|log()]] 的一個快捷方式。當足夠的消息被記錄或者當應用結(jié)束時,日志對象將會調(diào)用一個 [[yii\log\Dispatcher|message dispatcher]]調(diào)度對象將已經(jīng)記錄的日志消息發(fā)送到已注冊的 log targets 目標中。

日志目標

一個日志目標是一個 [[yii\log\Target]] 類或者它的子類的實例。它將通過他們的嚴重層級和類別來過濾日志消息,然后將它們導出到一些媒介中。例如,一個 [[yii\log\DbTarget|database target]] 目標導出已經(jīng)過濾的日志消息到一個數(shù)據(jù)的表里面,而一個 [[yii\log\EmailTarget|email target]]目標將日志消息導出到指定的郵箱地址里。

在一個應用里,通過配置在應用配置里的 log application component ,你可以注冊多個日志目標。就像下面這樣:

return [
    // the "log" component must be loaded during bootstrapping time
    'bootstrap' => ['log'],

    'components' => [
        'log' => [
            'targets' => [
                [
                    'class' => 'yii\log\DbTarget',
                    'levels' => ['error', 'warning'],
                ],
                [
                    'class' => 'yii\log\EmailTarget',
                    'levels' => ['error'],
                    'categories' => ['yii\db\*'],
                    'message' => [
                       'from' => ['log@example.com'],
                       'to' => ['admin@example.com', 'developer@example.com'],
                       'subject' => 'Database errors at example.com',
                    ],
                ],
            ],
        ],
    ],
];

注意:log 組件必須在 bootstrapping 期間就被加載,以便于它能夠及時調(diào)度日志消息到目標里。這是為什么在上面的代碼中,它被列在 bootstrap 數(shù)組中的原因。

在上面的代碼中,在 [[yii\log\Dispatcher::targets]] 屬性里有兩個日志目標被注冊:

  • 第一個目標選擇的是錯誤和警告層級的消息,并且在數(shù)據(jù)庫表里保存他們;
  • 第二個目標選擇的是錯誤層級的消息并且是在以 yii\db\ 開頭的分類下,并且在一個郵件里將它們發(fā)送到 admin@example.comdeveloper@example.com。

Yii 配備了以下的內(nèi)建日志目標。請參考關(guān)于這些類的 API 文檔,并且學習怎樣配置和使用他們。

  • [[yii\log\DbTarget]]:在數(shù)據(jù)庫表里存儲日志消息。
  • [[yii\log\EmailTarget]]:發(fā)送日志消息到預先指定的郵箱地址。
  • [[yii\log\FileTarget]]:保存日志消息到文件中.
  • [[yii\log\SyslogTarget]]:通過調(diào)用 PHP 函數(shù) syslog() 將日志消息保存到系統(tǒng)日志里。

下面,我們將描述所有日志目標的公共特性。

消息過濾

對于每一個日志目標,你可以配置它的 [[yii\log\Target::levels|levels]] 和 [[yii\log\Target::categories|categories]] 屬性來指定哪個消息的嚴重程度和分類目標應該處理。

[[yii\log\Target::levels|levels]] 屬性是由一個或者若干個以下值組成的數(shù)組:

  • error:相應的消息通過 [[Yii::error()]] 被記錄。
  • warning:相應的消息通過 [[Yii::warning()]] 被記錄。
  • info:相應的消息通過 [[Yii::info()]] 被記錄。
  • trace:相應的消息通過 [[Yii::trace()]] 被記錄。
  • profile:相應的消息通過 [[Yii::beginProfile()]] 和 [[Yii::endProfile()]] 被記錄。更多細節(jié)將在Profiling 分段解釋。

如果你沒有指定 [[yii\log\Target::levels|levels]] 的屬性,那就意味著目標將處理 任何 嚴重程度的消息。

[[yii\log\Target::categories|categories]] 屬性是一個包含消息分類名稱或者模式的數(shù)組。 一個目標將只處理那些在這個數(shù)組中能夠找到對應的分類或者其中一個相匹配的模式的消息。一個分類模式是一個以星號 * 結(jié)尾的分類名前綴。假如一個分類名與分類模式具有相同的前綴,那么該分類名將和分類模式相匹配。例如,yii\db\Command::executeyii\db\Command::query 都是作為分類名稱運用在 [[yii\db\Command]] 類來記錄日志消息的。它們都是匹配模式 yii\db\*。

假如你沒有指定 [[yii\log\Target::categories|categories]] 屬性,這意味著目標將會處理 任何 分類的消息。

除了通過 [[yii\log\Target::categories|categories]] 屬性設(shè)置白名單分類,你也可以通過 [[yii\log\Target::except|except]] 屬性來設(shè)置某些分類作為黑名單。假如一條消息的分類在這個屬性中被發(fā)現(xiàn)或者是匹配其中一個,那么它將不會在目標中被處理。

在下面的目標配置中指明了目標應該只處理錯誤和警告消息,當分類的名稱匹配 yii\db\* 或者是 yii\web\HttpException:* 的時候,但是除了 yii\web\HttpException:404。

[
    'class' => 'yii\log\FileTarget',
    'levels' => ['error', 'warning'],
    'categories' => [
        'yii\db\*',
        'yii\web\HttpException:*',
    ],
    'except' => [
        'yii\web\HttpException:404',
    ],
]

信息:當一個 HTTP 異常通過 error handler 被捕獲的時候,一個錯誤消息將以 yii\web\HttpException:ErrorCode這樣的格式的分類名被記錄下來。例如,[[yii\web\NotFoundHttpException]] 將會引發(fā)一個分類是 yii\web\HttpException:404 的錯誤消息。

消息格式化

日志目標以某種格式導出過濾過的日志消息。例如,假如你安裝一個 [[yii\log\FileTarget]] 類的日志目標,你應該能找出一個日志消息類似下面的 runtime/log/app.log 文件:

2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug

默認情況下,日志消息將被格式化,格式化的方式遵循 [[yii\log\Target::formatMessage()]]:

Timestamp [IP address][User ID][Session ID][Severity Level][Category] Message Text

你可以通過配置 [[yii\log\Target::prefix]] 的屬性來自定義格式,這個屬性是一個 PHP 可調(diào)用體返回的自定義消息前綴。例如,下面的代碼配置了一個日志目標的前綴是每個日志消息中當前用戶的 ID(IP 地址和 Session ID 被刪除是由于隱私的原因)。

[
    'class' => 'yii\log\FileTarget',
    'prefix' => function ($message) {
        $user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
        $userID = $user ? $user->getId(false) : '-';
        return "[$userID]";
    }
]

除了消息前綴以外,日志目標也可以追加一些上下文信息到每組日志消息中。默認情況下,這些全局的 PHP 變量的值被包含在:$_GET, $_POST, $_FILES, $_COOKIE,$_SESSION$_SERVER 中。你可以通過配置 [[yii\log\Target::logVars]] 屬性適應這個行為,這個屬性是你想要通過日志目標包含的全局變量名稱。舉個例子,下面的日志目標配置指明了只有 $_SERVER 變量的值將被追加到日志消息中。

[
    'class' => 'yii\log\FileTarget',
    'logVars' => ['_SERVER'],
]

你可以將 logVars 配置成一個空數(shù)組來完全禁止上下文信息包含?;蛘呒偃缒阆胍獙崿F(xiàn)你自己提供上下文信息的方式,你可以重寫 [[yii\log\Target::getContextMessage()]] 方法。

消息跟蹤級別

在開發(fā)的時候,通常希望看到每個日志消息來自哪里。這個是能夠被實現(xiàn)的,通過配置 log 組件的 [[yii\log\Dispatcher::traceLevel|traceLevel]] 屬性,就像下面這樣:

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [...],
        ],
    ],
];

上面的應用配置設(shè)置了 [[yii\log\Dispatcher::traceLevel|traceLevel]] 的層級,假如 YII_DEBUG 開啟則是 3,否則是 0。這意味著,假如 YII_DEBUG 開啟,每個日志消息在日志消息被記錄的時候,將被追加最多 3 個調(diào)用堆棧層級;假如 YII_DEBUG 關(guān)閉,那么將沒有調(diào)用堆棧信息被包含。

信息:獲得調(diào)用堆棧信息并不是不重要。因此,你應該只在開發(fā)或者調(diào)試一個應用的時候使用這個特性。

消息刷新和導出

如上所述,通過 [[yii\log\Logger|logger object]] 對象,日志消息被保存在一個數(shù)組里。為了這個數(shù)組的內(nèi)存消耗,當數(shù)組積累了一定數(shù)量的日志消息,日志對象每次都將刷新被記錄的消息到 log targets 中。你可以通過配置 log 組件的 [[yii\log\Dispatcher::flushInterval|flushInterval]] 屬性來自定義數(shù)量:

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'flushInterval' => 100,   // default is 1000
            'targets' => [...],
        ],
    ],
];

信息:當應用結(jié)束的時候,消息刷新也會發(fā)生,這樣才能確保日志目標能夠接收完整的日志消息。

當 [[yii\log\Logger|logger object]] 對象刷新日志消息到 log targets 的時候,它們并不能立即獲取導出的消息。相反,消息導出僅僅在一個日志目標累積了一定數(shù)量的過濾消息的時候才會發(fā)生。你可以通過配置個別的 log targets 的 [[yii\log\Target::exportInterval|exportInterval]] 屬性來自定義這個數(shù)量,就像下面這樣:

[
    'class' => 'yii\log\FileTarget',
    'exportInterval' => 100,  // default is 1000
]

因為刷新和導出層級的設(shè)置,默認情況下,當你調(diào)用 Yii::trace() 或者任何其他的記錄方法,你將不能在日志目標中立即看到日志消息。這對于一些長期運行的控制臺應用來說可能是一個問題。為了讓每個日志消息在日志目標中能夠立即出現(xiàn),你應該設(shè)置 [[yii\log\Dispatcher::flushInterval|flushInterval]]和 [[yii\log\Target::exportInterval|exportInterval]] 都為 1,就像下面這樣:

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'flushInterval' => 1,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'exportInterval' => 1,
                ],
            ],
        ],
    ],
];

注意:頻繁的消息刷新和導出將降低你到應用性能。

切換日志目標

你可以通過配置 [[yii\log\Target::enabled|enabled]] 屬性來開啟或者禁用日志目標。你可以通過日志目標配置去做,或者是在你的代碼中放入下面的 PHP 申明:

Yii::$app->log->targets['file']->enabled = false;

上面的代碼要求您將目標命名為 file,像下面展示的那樣,在 targets 數(shù)組中使用使用字符串鍵:

return [
    'bootstrap' => ['log'],
    'components' => [
        'log' => [
            'targets' => [
                'file' => [
                    'class' => 'yii\log\FileTarget',
                ],
                'db' => [
                    'class' => 'yii\log\DbTarget',
                ],
            ],
        ],
    ],
];

創(chuàng)建新的目標

創(chuàng)建一個新的日志目標類非常地簡單。你主要需要實現(xiàn) [[yii\log\Target::export()]] 方法來發(fā)送 [[yii\log\Target::messages]] 數(shù)組的內(nèi)容到一個指定的媒體中。你可以調(diào)用 [[yii\log\Target::formatMessage()]] 方法去格式化每個消息。更多細節(jié),你可以參考任何一個包含在 Yii發(fā)布版中的日志目標類。

性能分析

性能分析是一個特殊的消息記錄類型,它通常用在測量某段代碼塊的時間,并且找出性能瓶頸是什么。舉個例子,[[yii\db\Command]] 類使用性能分析找出每個數(shù)據(jù)庫查詢的時間。

為了使用性能分析,首先確定需要進行分析的代碼塊。然后像下面這樣圍住每個代碼塊:

\Yii::beginProfile('myBenchmark');

...code block being profiled...

\Yii::endProfile('myBenchmark');

這里的 myBenchmark 代表一個唯一標記來標識一個代碼塊。之后當你檢查分析結(jié)果的時候,你將使用這個標記來定位對應的代碼塊所花費的時間。

對于確保 beginProfileendProfile 對能夠正確地嵌套,這是很重要的。例如,

\Yii::beginProfile('block1');

    // some code to be profiled

    \Yii::beginProfile('block2');
        // some other code to be profiled
    \Yii::endProfile('block2');

\Yii::endProfile('block1');

假如你漏掉 \Yii::endProfile('block1') 或者切換了 \Yii::endProfile('block1')\Yii::endProfile('block2') 的順序,那么性能分析將不會工作。

對于每個被分析的代碼塊,一個帶有嚴重程度 profile 的日志消息被記錄。你可以配置一個 log target 去收集這些消息,并且導出他們。Yii debugger有一個內(nèi)建的性能分析面板能夠展示分析結(jié)果。

上一篇:國際化下一篇:Active Record