PHP日誌記錄工具Monolog

github地址:https://github.com/Seldaek/monolog

使用 Monolog

  • 安裝
  • 核心概念
  • 日誌級別
  • 配置一個日誌服務
  • 爲記錄添加額外的數據
  • 使用通道
  • 自定義日誌格式

Monolog是php下比較全又容易擴展的記錄日誌組件。目前有包括Symfony 、Laravel、 CakePHP等諸多知名php框架都內置了Monolog。

Monolog可以把你的日誌發送到文件,sockets,收件箱,數據庫和各種web服務器上。一些特殊的組件可以給你帶來特殊的日誌策略。

安裝

Monolog 在 Packagist (monolog/monolog) 上可用,並且可以通過 Composer 安裝:

composer require monolog/monolog

如果你不使用 Composer, 那你可以從 GitHub 上獲取代碼,然後使用任何兼容 PSR-0 的自動加載器(比如Symfony2 ClassLoader 組件)來加載 Monolog 的類

核心概念

每一個日誌服務實例 (Logger) 都有一個通道(名稱),並有一個處理器 (Handler)棧. 無論何時你添加一條 記錄 到對應的日誌服務實例,這個處理器棧將被遍歷一遍:每個處理器都將依次決定是否要處理這條記錄,而如果要處理,則遍歷結束(譯註:類似DOM事件冒泡)。

這樣子可以創建非常靈活的日誌配置。比如一個 StreamHandler 可以把所有日誌都寫入磁盤,而上面加個MailHandler 可以把錯誤日誌作爲郵件發送出去。處理器還有一個 $bubble 屬性定義了是否屏蔽某條記錄或者處理了某條記錄。在這個示例中,配置 MailHandler$bubble 參數爲 false 則意味着 MailHandler 將不會把自己已處理過的記錄繼續冒泡給 StreamHandler.

你可以創建許多日誌服務實例(Logger),每一個則定義一個通道(比如數據庫、請求、路由...)。而每一個日誌服務實例都可以組合各種各樣的處理器,可以共享處理器也可以不共享。這個通道將會在日誌中反映出來,從而允許你可以很容易地查看或者篩選記錄。

每一個處理還會有一個格式化器(Formatter)。如果你沒有配置一個,則一個有意義的默認的格式化器將被創建。格式化器用來規範化並格式化輸入的記錄,以便處理器能輸出一些有用的信息。

不支持自定義的嚴重性級別。只支持使用RFC 5424中定義的八個級別(調試/Debug、信息/Info、提示/Notice、警告/Warning、錯誤/Error、嚴重/Critical、警報/Alert、緊急/Emergency)來作爲基本的篩選目的。不過,如果爲了排序或者其他需要靈活性的使用場景,你可以添加加工程序(Processor)從而可以在(處理器)處理前添加額外的信息(標籤、用戶IP...)。

日誌級別

Monolog 支持一下 RFC 5424 中的日誌級別:

  • 調試/DEBUG (100): 詳細的調試信息。
  • 信息/INFO (200): 有意義的事件,比如用戶登錄、SQL日誌。
  • 提示/NOTICE (250): 正常但是值得注意的事件。
  • 警告/WARNING (300): 異常事件,但是並不是錯誤。比如使用了廢棄了的API,錯誤地使用了一個API,以及其他不希望發生但是並非必要的錯誤。
  • 錯誤/ERROR (400): 運行時的錯誤,不需要立即注意到,但是需要被專門記錄並監控到。
  • 嚴重/CRITICAL (500): 邊界條件/危篤場景。比如應用組件不可用了,未預料到的異常。
  • 警報/ALERT (550): 必須立即採取行動。比如整個網站都掛了,數據庫不可用了等。這種情況應該發送短信警報,並把你叫醒。
  • 緊急/EMERGENCY (600): 緊急請求:系統不可用了。

配置一個日誌服務

這裏有一個基本的配置,可以記錄日誌到文件,並在 DEBUG 級別下記錄到 firephp 中:

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// 創建日誌服務
$logger = new Logger('my_logger');

// 添加一些處理器
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());

// 現在你就可以用日誌服務了
$logger->info('My logger is now ready');

解釋一下。第一步是創建日誌服務實例,這個實例後將在代碼中用到。唯一的參數是通道的名稱,它在你有多個日誌服務實例的時候很有用。(更多詳情參見下面)

這個日誌服務實例自己是不是知道如何處理一條日誌記錄的。它把記錄代理給了一些處理器。上面的代碼中註冊了兩個處理器到棧中,以便允許使用兩種不同的方式來處理日誌記錄。

注意,FirePHPHandler 是被先調用的,因而它被添加到了棧頂。這允許你臨時添加一個禁止冒泡的處理器從而允許你覆蓋其他配置的日誌(處理器)。

如果你單獨使用 Monolog, 並且在尋找一種簡單的方式來配置許多處理器,那可以用
theorchard/monolog-cascade
它可以幫你使用PHP數組、YAML或者JSON來構建複雜的日誌配置。

爲記錄添加額外的數據

Monolog 提供了兩種不同的方式來爲簡單的文本消息增加額外的信息

使用上下文(context)

第一種方式是使用上下文(context),這允許你在傳遞記錄的時候傳遞一個數組格式的數據:

<?php
$logger->info('Adding a new user', array('username' => 'Seldaek'));

簡單的處理器(比如StreamHandler)將只是把數組轉換成字符串。而複雜的處理器則可以利用上下文的優點(如 FirePHP 則將以一種優美的方式顯示數組)。

使用加工程序(Processor)

第二種方式是使用加工程序來爲所有的記錄添加額外數據。加工程序可以是任何可以調用的函數。
加工程序接收日誌記錄作爲參數,並且需要在修改了extra字段後再返回日誌記錄。讓我們來寫一個添加一些假數據的加工程序:

<?php
$logger->pushProcessor(function ($record) {
    $record['extra']['dummy'] = 'Hello world!';
    return $record;
});

Monolog提供了一些內置的加工程序,你可以在你的項目中使用它們。

小技巧:加工程序可以被註冊到一個特定的處理器上而不是直接在日誌服務實例上,從而可以只在對應的處理器上生效。

使用通道

通道是一種非常棒的方式來區分是應用的哪個部分的日誌被記錄下來的。這通常在大型項目中非常有用(而且被Symfony2的MonologBundle所使用)。

假設有兩個日誌服務實例共享了一個處理器,這個處理器將日誌寫入單個日誌文件。通道則將允許你來區分是哪個日誌服務實例記錄了哪條日誌。你可以很簡單地通過通道來篩選日誌。

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// 創建一些處理器
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$firephp = new FirePHPHandler();

// 創建應用的主要日誌服務實例
$logger = new Logger('my_logger');
$logger->pushHandler($stream);
$logger->pushHandler($firephp);

// 使用另外的通道來創建安全相關的日誌服務示例
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);
$securityLogger->pushHandler($firephp);

// 或者克隆第一個,只是改變下通道
$securityLogger = $logger->withName('security');

自定義日誌格式

在Monolog中,可以很簡單地來自定義日誌的格式,無論是寫入文件、套接字、郵件、數據庫還是其他處理器。大多數處理器都是用 $record['formatted'] 這個值來自動寫入日誌設備。這個值依賴格式化器的配置。你可以選擇預定義的格式化器類,也可以自己寫一個(比如一個可讀的多行文本文件)。

想要配置一個預定義的格式化器類,可以直接把它設置爲處理器的字段:

// 默認的日期格式是 "Y-m-d H:i:s"
$dateFormat = "Y n j, g:i a";
// 默認的輸出格式是 "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
// 最後創建一個格式化器
$formatter = new LineFormatter($output, $dateFormat);

// 創建一個處理器
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$stream->setFormatter($formatter);

// 將其綁定到日誌服務對象上
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);

你還可以在多個處理器之間複用同一個格式化器,並且在多個日誌服務實例間共享這些處理器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章