[PHP 類庫] Monolog - Logging for PHP 5.3+

Monolog是PHP的一個日誌類庫。相比於其餘的日誌類庫,它有如下的特色:php

  • 功能強大。能夠把日誌發送到文件、socket、郵箱、數據庫和各類web services。
  • 遵循PSR3的接口規範。能夠很輕易的替換成其餘遵循同一規範的日誌類庫。
  • 良好的擴展性。經過HandlerFormatterProcessor這幾個接口,能夠對Monolog類庫進行各類擴展和自定義。

基本用法

安裝最新版本:html

composer require monolog/monolog

要求PHP版本爲5.3以上。git

php<?php

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

// 建立日誌頻道
$log = new Logger('name');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));

// 添加日誌記錄
$log->addWarning('Foo');
$log->addError('Bar');

核心概念

每個Logger實例都包含一個頻道名(channel)和handler的堆棧。當你添加一條記錄時,記錄會依次經過handler堆棧的處理。而每一個handler也能夠決定是否把記錄傳遞到下一個堆棧裏的下一個handler。github

經過handler,咱們能夠實現一些複雜的日誌操做。例如咱們把StreamHandler放在堆棧的最下面,那麼全部的日誌記錄最終都會寫到硬盤文件裏。同時咱們把MailHandler放在堆棧的最上面,經過設置日誌等級把錯誤日誌經過郵件發送出去。Handler裏有個$bubble屬性,這個屬性定義了handler是否攔截記錄不讓它流到下一個handler。因此若是咱們把MailHandler$bubble參數設置爲false,則出現錯誤日誌時,日誌會經過MailHandler發送出去,而不會通過StreamHandler寫到硬盤上。web

Logger能夠建立多個,每一個均可以定義本身的頻道名和handler堆棧。handler能夠在多個Logger中共享。頻道名會反映在日誌裏,方便咱們查看和過濾日誌記錄。sql

若是沒有指定日誌格式(Formatter),Handler會使用默認的Formatter。數據庫

日誌的等級不能自定義,目前使用的是RFC 5424裏定義的8個等級:debug、info、notice、warning、error、critical、alert和emergency。若是對日誌記錄有其餘的需求,能夠經過Processo對日誌記錄添加內容。數組

日誌等級

  • DEBUG (100): 詳細的debug信息。
  • INFO (200): 關鍵事件。
  • NOTICE (250): 普通可是重要的事件。
  • WARNING (300): 出現非錯誤的異常。
  • ERROR (400): 運行時錯誤,可是不須要馬上處理。
  • CRITICA (500): 嚴重錯誤。
  • EMERGENCY (600): 系統不可用。

用法詳解

多個handler

php<?php

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

// 建立Logger實例
$logger = new Logger('my_logger');
// 添加handler
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());

// 開始使用
$logger->addInfo('My logger is now ready');

第一步咱們先建立一個Logger實例,傳入的是頻道名,這個頻道名能夠用於區分多個Logger實例。瀏覽器

實例自己並不知道如何處理日誌記錄,它是經過handler進行處理的。handler能夠設置多個,例如上面的例子設置了兩個handler,能夠對日誌記錄進行兩種不一樣方式的處理。緩存

須要注意的是,因爲handler是採用堆棧的方式保存,因此後面添加的handler位於棧頂,會首先被調用。

添加額外的數據

Monolog有兩種方式對日誌添加額外的信息。

使用上下文

第一個方法是使用$context參數,傳入一個數組:

php<?php

$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));

使用processor

第二個方法是使用processor。processor能夠是任何可調用的方法,這些方法把日誌記錄做爲參數,而後通過處理修改extra部分後返回。

php<?php

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

    return $record;
});

Processor不必定要綁定在Logger實例上,也能夠綁定到某個具體的handler上。使用handler實例的pushProcessor方法進行綁定。

頻道的使用

使用頻道名能夠對日誌進行分類,這在大型的應用上是頗有用的。經過頻道名,能夠很容易的對日誌記錄進行刷選。

例如咱們想在同一個日誌文件裏記錄不一樣模塊的日誌,咱們能夠把相同的handler綁定到不一樣的Logger實例上,這些實例使用不一樣的頻道名:

php<?php

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

// 建立handler
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$firephp = new FirePHPHandler();

// 建立應用的主要logger
$logger = new Logger('my_logger');
$logger->pushHandler($stream);
$logger->pushHandler($firephp);

// 經過不一樣的頻道名建立一個用於安全相關的logger
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);
$securityLogger->pushHandler($firephp);

Handler

Monolog內置不少很實用的handler,它們幾乎囊括了各類的使用場景,這裏介紹一些使用的:

  • StreamHandler:把記錄寫進PHP流,主要用於日誌文件。
  • SyslogHandler:把記錄寫進syslog。
  • ErrorLogHandler:把記錄寫進PHP錯誤日誌。
  • NativeMailerHandler:使用PHP的mail()函數發送日誌記錄。
  • SocketHandler:經過socket寫日誌。
php<?php

use Monolog\Logger;
use Monolog\Handler\SocketHandler;

// Create the logger
$logger = new Logger('my_logger');

// Create the handler
$handler = new SocketHandler('unix:///var/log/httpd_app_log.socket');
$handler->setPersistent(true);

// Now add the handler
$logger->pushHandler($handler, Logger::DEBUG);

// You can now use your logger
$logger->addInfo('My logger is now ready');
  • AmqpHandler:把記錄寫進兼容amqp協議的服務。
  • BrowserConsoleHandler:把日誌記錄寫到瀏覽器的控制檯。因爲是使用瀏覽器的console對象,須要看瀏覽器是否支持。
  • RedisHandler:把記錄寫進Redis。
  • MongoDBHandler:把記錄寫進Mongo。
  • ElasticSearchHandler:把記錄寫到ElasticSearch服務。
  • BufferHandler:容許咱們把日誌記錄緩存起來一次性進行處理。

更多的Handler請看 https://github.com/Seldaek/monolog#handlers

Formatter

一樣的,這裏介紹幾個自帶的Formatter:

  • LineFormatter:把日誌記錄格式化成一行字符串。
  • HtmlFormatter:把日誌記錄格式化成HTML表格,主要用於郵件。
  • JsonFormatter:把日誌記錄編碼成JSON格式。
  • LogstashFormatter:把日誌記錄格式化成logstash的事件JSON格式。
  • ElasticaFormatter:把日誌記錄格式化成ElasticSearch使用的數據格式。

更多的Formatter請看 https://github.com/Seldaek/monolog#formatters

Processor

前面說過,Processor能夠爲日誌記錄添加額外的信息,Monolog也提供了一些很實用的processor:

  • IntrospectionProcessor:增長當前腳本的文件名和類名等信息。
  • WebProcessor:增長當前請求的URI、請求方法和訪問IP等信息。
  • MemoryUsageProcessor:增長當前內存使用狀況信息。
  • MemoryPeakUsageProcessor:增長內存使用高峯時的信息。

更多的Processor請看 https://github.com/Seldaek/monolog#processors

擴展handler

Monolog內置了不少handler,可是並非全部場景都能覆蓋到,有時須要本身去定製handler。寫一個handler並不難,只須要實現Monolog\Handler\HandlerInterface這個接口便可。

下面這個例子實現了把日誌記錄寫到數據庫裏。咱們不須要把接口裏的方法所有實現一次,能夠直接使用Monolog提供的抽象類AbstractProcessingHandler進行繼承,實現裏面的write方法便可。

php<?php

use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;

class PDOHandler extends AbstractProcessingHandler
{
    private $initialized = false;
    private $pdo;
    private $statement;

    public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true)
    {
        $this->pdo = $pdo;
        parent::__construct($level, $bubble);
    }

    protected function write(array $record)
    {
        if (!$this->initialized) {
            $this->initialize();
        }

        $this->statement->execute(array(
            'channel' => $record['channel'],
            'level' => $record['level'],
            'message' => $record['formatted'],
            'time' => $record['datetime']->format('U'),
        ));
    }

    private function initialize()
    {
        $this->pdo->exec(
            'CREATE TABLE IF NOT EXISTS monolog '
            .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
        );
        $this->statement = $this->pdo->prepare(
            'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
        );
    }
}

而後咱們就可使用它了:

php<?php

$logger->pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite'));

// You can now use your logger
$logger->addInfo('My logger is now ready');

參考

https://github.com/Seldaek/monolog

相關文章
相關標籤/搜索