PSR-3: Logger Interface 読了

# PSRとは
- PSR（PHP Standards Recommendations）とは、[PHP-FIG](https://www.php-fig.org/)（PHP Framework Interop Group）が策定しているPHPコーディング規約を指す

# PSR-3: Logger Interface
[PSR-3: Logger Interface](https://www.php-fig.org/psr/psr-3/)

>This document describes a common interface for logging libraries.

>The main goal is to allow libraries to receive a Psr\Log\LoggerInterface object and write logs to it in a simple and universal way. Frameworks and CMSs that have custom needs MAY extend the interface for their own purpose, but SHOULD remain compatible with this document. This ensures that the third-party libraries an application uses can write to the centralized application logs.

>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

>The word implementor in this document is to be interpreted as someone implementing the LoggerInterface in a log-related library or framework. Users of loggers are referred to as user.

- このドキュメントでは、ロギングライブラリの一般的なインターフェイスについて記されている
- 主な目的は、このライブラリがPsr\Log\LoggerInterfaceオブジェクトを受け取り、シンプルで普遍的な方法でログを書き込むことにある
- フレームワークとCMSは、独自の目的のためにインターフェースを拡張できるが、このドキュメントとの互換性を維持する必要がある
- これにより、アプリケーションが使用するサードパーティライブラリが集約化されたアプリケーションログに書き込むことができる
- このドキュメントの実装者という言葉は、ログ関連のライブラリまたはフレームワークでLoggerInterfaceを実装している人として解釈する
- いくつか登場するキーワード（MUST, MUST NOT etc...）は、[RFC 2119](https://tools.ietf.org/html/rfc2119)で説明されてるような解釈とする

内容の構成は**章立て**されており、いくつかの章では節に当たる項目が用意されてる
引用に関しては全て**PSR-1**のものである
箇条書きされてる箇所は **和訳＋個人の解釈** の入った内容となってる

※以下、学習の一環として自分の解釈とコードを交えた内容を記載しますが、間違いあればコメント頂けますと幸いです。早急に対応しますのでご遠慮なく。

## 1. 仕様
https://www.php-fig.org/psr/psr-3/#1-specification


### 1.1基本
>The LoggerInterface exposes eight methods to write logs to the eight RFC 5424 levels (debug, info, notice, warning, error, critical, alert, emergency).
>
>A ninth method, log, accepts a log level as the first argument. Calling this method with one of the log level constants MUST have the same result as calling the level-specific method. Calling this method with a level not defined by this specification MUST throw a Psr\Log\InvalidArgumentException if the implementation does not know about the level. Users SHOULD NOT use a custom level without knowing for sure the current implementation supports it.

- LoggerInterfaceは、ログを8つの[RFC 5424レベル](https://tools.ietf.org/html/rfc5424)（debug, info, notice, warning, error, critical, alert, emergency）に書き込むために8つのメソッドを公開してる
- 9番目のlogメソッドは、最初の引数としてログレベルを受け取る、ログレベル定数のいずれかでこのメソッドを呼び出した場合は、そのレベル固有のメソッドを呼び出した場合と同じ結果を返さなければならない
- この仕様で定義されていないレベルでlogメソッドを呼び出す場合は、Psr\Log\InvalidArgumentExceptionをスローする必要がある
- ログレベルを確認せずカスタムレベルを使用してはいけない

### 1.2 Message
>Every method accepts a string as the message, or an object with a __toString() method. Implementors MAY have special handling for the passed objects. If that is not the case, implementors MUST cast it to a string.

>The message MAY contain placeholders which implementors MAY replace with values from the context array.

>Placeholder names MUST correspond to keys in the context array.

>Placeholder names MUST be delimited with a single opening brace { and a single closing brace }. There MUST NOT be any whitespace between the delimiters and the placeholder name.

>Placeholder names SHOULD be composed only of the characters A-Z, a-z, 0-9, underscore _, and period .. The use of other characters is reserved for future modifications of the placeholders specification.

>Implementors MAY use placeholders to implement various escaping strategies and translate logs for display. Users SHOULD NOT pre-escape placeholder values since they can not know in which context the data will be displayed.

- すべてのメソッドは、メッセージとして文字列、または__toString()メソッドを持つオブジェクトを受けとることができるが、そうではない場合文字列にキャストしなければならない
- コンテキストな配列にはプレースホルダーに置き換えることができる値が含まれてる場合がある
- プレースホルダー名は、配列のキーに対応する必要がある
- プレースホルダー名は、中括弧{}で区切る必要がある
- 区切り文字とプレースホルダー名の間に空白があってはいけない
- プレースホルダ名は、**A〜Z、a〜z、0〜9、アンダースコア、およびピリオドのみ**で構成しなければならない
- プレースホルダーをエスケープして表示用のログを変換することができるため、プレースホルダーを事前にエスケープしてはいけない

>The following is an example implementation of placeholder interpolation provided for reference purposes only:

```php
<?php

/**
 * Interpolates context values into the message placeholders.
 */
function interpolate($message, array $context = array())
{
    // build a replacement array with braces around the context keys
    $replace = array();
    foreach ($context as $key => $val) {
        // check that the value can be casted to string
        if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
            $replace['{' . $key . '}'] = $val;
        }
    }

    // interpolate replacement values into the message and return
    return strtr($message, $replace);
}

// a message with brace-delimited placeholder names
$message = "User {username} created";

// a context array of placeholder names => replacement values
$context = array('username' => 'bolivar');

// echoes "User bolivar created"
echo interpolate($message, $context);
```

### 1.3 コンテキスト
>Every method accepts an array as context data. This is meant to hold any extraneous information that does not fit well in a string. The array can contain anything. Implementors MUST ensure they treat context data with as much lenience as possible. A given value in the context MUST NOT throw an exception nor raise any php error, warning or notice.

>If an Exception object is passed in the context data, it MUST be in the 'exception' key. Logging exceptions is a common pattern and this allows implementors to extract a stack trace from the exception when the log backend supports it. Implementors MUST still verify that the 'exception' key is actually an Exception before using it as such, as it MAY contain anything.

- 全てのメソッドは引数としてコンテキストデータを配列として受け取る
- コンテキスト内の値に対して例外をスローしたりPHPエラー、警告、通知を発生してはいけない

### 1.4 ヘルパークラスとインターフェイス
>The Psr\Log\AbstractLogger class lets you implement the LoggerInterface very easily by extending it and implementing the generic log method. The other eight methods are forwarding the message and context to it.

>Similarly, using the Psr\Log\LoggerTrait only requires you to implement the generic log method. Note that since traits can not implement interfaces, in this case you still have to implement LoggerInterface.

>The Psr\Log\NullLogger is provided together with the interface. It MAY be used by users of the interface to provide a fall-back “black hole” implementation if no logger is given to them. However, conditional logging may be a better approach if context data creation is expensive.

>The Psr\Log\LoggerAwareInterface only contains a setLogger(LoggerInterface $logger) method and can be used by frameworks to auto-wire arbitrary instances with a logger.

>The Psr\Log\LoggerAwareTrait trait can be used to implement the equivalent interface easily in any class. It gives you access to $this->logger.

>The Psr\Log\LogLevel class holds constants for the eight log levels.

- **Psr\Log\AbstractLoggerクラス**を使用して汎用的なログメソッドを実装することで、拡張したLoggerInterfaceを簡単に実装することができる
- 他にはメッセージとコンテキストの転送を行う8つのメソッドが存在する
- **Psr\Log\LoggerTraitクラス**を使用するには一般的なログメソッドを実装するだけで良いが、LoggerInterfaceを実装する必要がある
- **Psr\Log\LoggerAwareInterfaceクラス**には`setLogger（LoggerInterface $logger）メソッド`のみ含まれ、フレームワークがロガーと任意のインスタンスを自動接続するために使用する
- **Psr\Log\LoggerAwareTraitクラス**の特性を使用することで同等のインターフェースを任意のクラスに実装することができる（$this->loggerでアクセスできる）
- **Psr\Log\LogLevelクラス**は、8つのログレベルの定数を保持する

## 2. パッケージ

https://www.php-fig.org/psr/psr-3/#2-package

>The interfaces and classes described as well as relevant exception classes and a test suite to verify your implementation are provided as part of the psr/log package.

- インターフェースとクラス、その他関連する例外クラスと実装を検証するためのテストはpsr/logパッケージの一部として提供されてる

## 3. Psr\Log\LoggerInterface

https://www.php-fig.org/psr/psr-3/#3-psrlogloggerinterface

```php
<?php

namespace Psr\Log;

/**
 * Describes a logger instance.
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data, the only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named "exception".
 *
 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
interface LoggerInterface
{
    /**
     * System is unusable.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function emergency($message, array $context = array());

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function alert($message, array $context = array());

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function critical($message, array $context = array());

    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function error($message, array $context = array());

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function warning($message, array $context = array());

    /**
     * Normal but significant events.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function notice($message, array $context = array());

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function info($message, array $context = array());

    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param array $context
     * @return void
     */
    public function debug($message, array $context = array());

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     * @param string $message
     * @param array $context
     * @return void
     */
    public function log($level, $message, array $context = array());
}
```

- [1. 仕様](https://qiita.com/drafts/3e531c6922d0e5cae8bd#1-%E4%BB%95%E6%A7%98)で記されてるように、LoggerInterfaceではログレベルに応じたログ内容を書き込むための8つのメソッドが実装されてる

## 4. Psr\Log\LoggerAwareInterface

https://www.php-fig.org/psr/psr-3/#4-psrlogloggerawareinterface

```php
<?php

namespace Psr\Log;

/**
 * Describes a logger-aware instance.
 */
interface LoggerAwareInterface
{
    /**
     * Sets a logger instance on the object.
     *
     * @param LoggerInterface $logger
     * @return void
     */
    public function setLogger(LoggerInterface $logger);
}
```

- [1. 仕様](https://qiita.com/drafts/3e531c6922d0e5cae8bd#1-%E4%BB%95%E6%A7%98)で記されてるように、LoggerAwareInterfaceではロガーと任意のインスタンスを接続するためのsetLoggerメソッドが実装されている

## 5. Psr\Log\LogLevel

https://www.php-fig.org/psr/psr-3/#5-psrlogloglevel

```php
<?php

namespace Psr\Log;

/**
 * Describes log levels.
 */
class LogLevel
{
    const EMERGENCY = 'emergency';
    const ALERT     = 'alert';
    const CRITICAL  = 'critical';
    const ERROR     = 'error';
    const WARNING   = 'warning';
    const NOTICE    = 'notice';
    const INFO      = 'info';
    const DEBUG     = 'debug';
}
```

- [1. 仕様](https://qiita.com/drafts/3e531c6922d0e5cae8bd#1-%E4%BB%95%E6%A7%98)で記されてるようにLogLevelクラスでは、8つのログレベル定数が定義されてる

# 注意
- 冒頭でも述べたように、主に箇条書きされてる箇所については、 **和訳＋個人の解釈** の入った内容になっているため、参考程度の理解としていただきたい
- また、表現に誤りがある場合、遠慮なくコメントいただけると幸いです（この内容に関しては表現の誤りは致命的なため）
- 学習の一環としてアウトプットしたいため投稿したので、その点暖かい目で読んで頂けると嬉しい