Monolog是PHP的一個日誌類庫。相比於其餘的日誌類庫,它有如下的特色:php
Handler
、Formatter
和Processor
這幾個接口,能夠對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對日誌記錄添加內容。數組
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能夠是任何可調用的方法,這些方法把日誌記錄做爲參數,而後通過處理修改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);
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:
LineFormatter
:把日誌記錄格式化成一行字符串。HtmlFormatter
:把日誌記錄格式化成HTML表格,主要用於郵件。JsonFormatter
:把日誌記錄編碼成JSON格式。LogstashFormatter
:把日誌記錄格式化成logstash的事件JSON格式。ElasticaFormatter
:把日誌記錄格式化成ElasticSearch使用的數據格式。更多的Formatter請看 https://github.com/Seldaek/monolog#formatters。
前面說過,Processor能夠爲日誌記錄添加額外的信息,Monolog也提供了一些很實用的processor:
IntrospectionProcessor
:增長當前腳本的文件名和類名等信息。WebProcessor
:增長當前請求的URI、請求方法和訪問IP等信息。MemoryUsageProcessor
:增長當前內存使用狀況信息。MemoryPeakUsageProcessor
:增長內存使用高峯時的信息。更多的Processor請看 https://github.com/Seldaek/monolog#processors。
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');