1. 程式人生 > >Monolog php日誌

Monolog php日誌

本文轉自https://blog.csdn.net/thinking771470736/article/details/80927889

Monolog 是PHP的一個日誌類庫。相比於其他的日誌類庫,它有以下的特點:

  • 功能強大。可以把日誌傳送到檔案、socket、郵箱、資料庫和各種web services。
  • 遵循 PSR3 的介面規範。可以很輕易的替換成其他遵循同一規範的日誌類庫。
  • 良好的擴充套件性。通過 Handler 、 Formatter 和 Processor 這幾個介面,可以對Monolog類庫進行各種擴充套件和自定義。

基本用法

安裝最新版本:

composer require monolog/monolog

要求PHP版本為5.3以上。

 
  1. <?php

  2. use Monolog\Logger;

  3. use Monolog\Handler\StreamHandler;

  4. // 建立日誌頻道

  5. $log = new Logger('name');

  6. $log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));

  7. // 新增日誌記錄

  8. $log->addWarning('Foo');

  9. $log->addError('Bar');

  1.  
  2.  

核心概念

每一個 Logger 例項都包含一個頻道名(channel)和handler的堆疊。當你新增一條記錄時,記錄會依次通過handler堆疊的處理。而每個handler也可以決定是否把記錄傳遞到下一個堆疊裡的下一個handler。

通過handler,我們可以實現一些複雜的日誌操作。例如我們把 StreamHandler 放在堆疊的最下面,那麼所有的日誌記錄最終都會寫到硬碟檔案裡。同時我們把 MailHandler

 放在堆疊的最上面,通過設定日誌等級把錯誤日誌通過郵件傳送出去。Handler裡有個 $bubble 屬性,這個屬性定義了handler是否攔截記錄不讓它流到下一個handler。所以如果我們把 MailHandler 的 $bubble 引數設定為 false ,則出現錯誤日誌時,日誌會通過 MailHandler 傳送出去,而不會經過 StreamHandler 寫到硬碟上。

Logger 可以建立多個,每個都可以定義自己的頻道名和handler堆疊。handler可以在多個 Logger 中共享。頻道名會反映在日誌裡,方便我們檢視和過濾日誌記錄。

如果沒有指定日誌格式(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

 
  1. <?php

  2. use Monolog\Logger;

  3. use Monolog\Handler\StreamHandler;

  4. use Monolog\Handler\FirePHPHandler;

  5. // 建立Logger例項

  6. $logger = new Logger('my_logger');

  7. // 新增handler

  8. $logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));

  9. $logger->pushHandler(new FirePHPHandler());

  10. // 開始使用

  11. $logger->addInfo('My logger is now ready');

  1.  

第一步我們先建立一個 Logger 例項,傳入的是頻道名,這個頻道名可以用於區分多個Logger 例項。

例項本身並不知道如何處理日誌記錄,它是通過handler進行處理的。handler可以設定多個,例如上面的例子設定了兩個handler,可以對日誌記錄進行兩種不同方式的處理。

需要注意的是,由於handler是採用堆疊的方式儲存,所以後面新增的handler位於棧頂,會首先被呼叫。

新增額外的資料

Monolog有兩種方式對日誌新增額外的資訊。

使用上下文

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

 
  1. <?php

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

  1.  

使用processor

第二個方法是使用processor。processor可以是任何可呼叫的方法,這些方法把日誌記錄作為引數,然後經過處理修改 extra 部分後返回。

 
  1. <?php

  2. $logger->pushProcessor(function ($record) {

  3. $record['extra']['dummy'] = 'Hello world!';

  4. return $record;

  5. });

  1.  

Processor不一定要繫結在Logger例項上,也可以繫結到某個具體的handler上。使用handler例項的 pushProcessor 方法進行繫結。

頻道的使用

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

例如我們想在同一個日誌檔案裡記錄不同模組的日誌,我們可以把相同的handler繫結到不同的Logger例項上,這些例項使用不同的頻道名:

 
  1. <?php

  2. use Monolog\Logger;

  3. use Monolog\Handler\StreamHandler;

  4. use Monolog\Handler\FirePHPHandler;

  5. // 建立handler

  6. $stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);

  7. $firephp = new FirePHPHandler();

  8. // 建立應用的主要logger

  9. $logger = new Logger('my_logger');

  10. $logger->pushHandler($stream);

  11. $logger->pushHandler($firephp);

  12. // 通過不同的頻道名建立一個用於安全相關的logger

  13. $securityLogger = new Logger('security');

  14. $securityLogger->pushHandler($stream);

  15. $securityLogger->pushHandler($firephp);

 

  1.  

Handler

Monolog內建很多很實用的handler,它們幾乎囊括了各種的使用場景,這裡介紹一些使用的:

  • StreamHandler :把記錄寫進PHP流,主要用於日誌檔案。
  • SyslogHandler :把記錄寫進syslog。
  • ErrorLogHandler :把記錄寫進PHP錯誤日誌。
  • NativeMailerHandler :使用PHP的 mail() 函式傳送日誌記錄。
  • SocketHandler :通過socket寫日誌。
 
  1.  
    1. <?php

    2. use Monolog\Logger;

    3. use Monolog\Handler\SocketHandler;

    4. // Create the logger

    5. $logger = new Logger('my_logger');

    6. // Create the handler

    7. $handler = new SocketHandler('unix:///var/log/httpd_app_log.socket');

    8. $handler->setPersistent(true);

    9. // Now add the handler

    10. $logger->pushHandler($handler, Logger::DEBUG);

    11. // You can now use your logger

    12. $logger->addInfo('My logger is now ready');

  2.  
  • 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方法即可。

  1.  
 
  1. <?php

  2. use Monolog\Logger;

  3. use Monolog\Handler\AbstractProcessingHandler;

  4. class PDOHandler extends AbstractProcessingHandler

  5. {

  6. private $initialized = false;

  7. private $pdo;

  8. private $statement;

  9.  
  10. public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true)

  11. {

  12. $this->pdo = $pdo;

  13. parent::__construct($level, $bubble);

  14. }

  15. protected function write(array $record)

  16. {

  17. if (!$this->initialized) {

  18. $this->initialize();

  19. }

  20. $this->statement->execute(array(

  21. 'channel' => $record['channel'],

  22. 'level' => $record['level'],

  23. 'message' => $record['formatted'],

  24. 'time' => $record['datetime']->format('U'),

  25. ));

  26. }

  27. private function initialize()

  28. {

  29. $this->pdo->exec(

  30. 'CREATE TABLE IF NOT EXISTS monolog '

  31. .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'

  32. );

  33. $this->statement = $this->pdo->prepare(

  34. 'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'

  35. );

  36. }

  37. }

 

然後我們就可以使用它了:

 
  1. <?php

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

  3. // You can now use your logger

  4. $logger->addInfo('My logger is now ready');