monolog 原始碼分析

blabla發表於2019-11-28

簡介

monolog是基於psr-3設計的日誌記錄元件。

monolog抽象層

Logger

日誌記錄總控類,通過pushHandler、popHandler、pushProcessor、popProcessor排兵佈陣。 根據PSR-3,Logger可以記錄8個不同等級的日誌資訊。

handler的種類豐富,以下例舉部分:
  • ElasticesearchHandler
  • ErrorLogHandler
  • PHPConsoleHandler
  • NullHandler
  • .....
processor的種類也不少,且可以自定義
  • GitProcessor 將git分支資訊和提交資訊加入到記錄($record)中
  • HostnameProcessor 在記錄中加入hostname資訊
  • .....

Handler

handler處理日誌記錄的具體事項。

AbstractProcessingHandler抽象類

一般情況下,handler都需繼承AbstractProcessingHandler抽象類。該類提供handler所必須的方法,實現ProcessableHandlerInterface和FormattableHandlerInterface介面以操作processor和formatter。

abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface
{
    use ProcessableHandlerTrait;
    use FormattableHandlerTrait;
    ......
}

繼承該類後,通過handler也可以實現出入棧processor及操作formatter。對processor和formatter的在呼叫在handle方法中實現。

 public function handle(array $record): bool
    {
        if (!$this->isHandling($record)) {
            return false;
        }

        if ($this->processors) {
            $record = $this->processRecord($record); //獲取processor日誌
        }

        $record['formatted'] = $this->getFormatter()->format($record); //格式化日誌

        $this->write($record);

        return false === $this->bubble;
    }

在ProcessableHandlerTrait中實現出入棧processor

 public function pushProcessor(callable $callback): HandlerInterface
    {
        array_unshift($this->processors, $callback);

        return $this;
    }

    public function popProcessor(): callable
    {
        if (!$this->processors) {
            throw new \LogicException('You tried to pop from an empty processor stack.');
        }

        return array_shift($this->processors);
    }

在FormattableHandlerTrait中設定formatter

public function setFormatter(FormatterInterface $formatter): HandlerInterface
    {
        $this->formatter = $formatter;

        return $this;
    }

    public function getFormatter(): FormatterInterface
    {
        if (!$this->formatter) {
            $this->formatter = $this->getDefaultFormatter();
        }

        return $this->formatter;
    }

Formatter

formatter用於日誌記錄的格式化,往往不同的handler有各自不同的formatter。比如ElasticsearchHandler有ElasticsearchFormatter。一個handler對應一個formatter。當沒有指定formatter時,handler就會呼叫預設的LineFormatter。LineFormatter將輸入的record格式化成一行的字串,主要用於將日誌記錄到檔案的場景。

class LineFormatter extends NormalizerFormatter
{
    ......
}

Processor

processor用來追加一些額外的記錄

你可以自定義processor

$logger->pushProcessor(function($record){
        $record['extra']['foo'] = 'bar';
        return $record;
    });

也可以使用monoglog自帶的。HostnameProcessor類實現了invoke靜態方法,當以呼叫函式的方式呼叫一個物件時,invoke方法會被自動呼叫。

$logger->pushProcessor(new \Monolog\Processor\HostnameProcessor);

monolog使用策略模式

monolog使用策略模式實現handler與processor、formatter的程式碼分離

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章