恥知らずのウェブエンジニア -web engineer, shameless

これは一歩を踏み出すことができない者たちのブログ

PSR-3(Logger Interface)を見ていく

要約ですので、所々省いている箇所あります。

オリジナルはこちら

www.php-fig.org

概要

  • ロギングライブラリの共通インターフェースのドキュメント
  • ゴールはライブラリがPsr\Log\LoggerInterfaceを受け入れることでログ出力をシンプルかつ共通化を行う
  • フレームワークCMSは必要によってインターフェースを拡張してもよいが、インターフェースを遵守しなければいけない
  • こうすることでサードパーティライブラリでもログを集約することができる

仕様

基礎

  • LoggerInterfaceは8個のメソッドを提供し、レベルは8個(debug, info, notice, warning, error, critical, alert, emergency)
  • 9番目のメソッドlogは第一引数にログレベルを受け取る。ログレベル定数の一つを受け取ったメソッドの結果は、各レベルごとのメソッドの結果と同じでなければならない
  • 定義されていないレベルを引数として受け取った場合、Psr\Log\InvalidArgumentExceptionをthrowしなければならない
  • ユーザはカスタムレベルを使うべきではありません

メッセージ

  • 各メソッドはメッセージとしてstringか、__toString()を持つオブジェクトを受け取る。
  • 実装者はオブジェクトを何らかハンドリングしてもよいですが、そのケースではない時は、stringにキャストしなければいけません
  • メッセージは配列の値から置換できるプレースホルダーを含んでもよい
  • プレースホルダーの命名は配列のキーと一致しなければならない
  • プレースホルダーは{}で囲まないといけない。囲んでいる中にホワイトスペースを入れてはいけない
  • プレースホルダーはA-Z, a-z, 0-9, _, .だけを使うべき。それ以外は今後のプレースホルダー仕様変更用に予約されています
  • 実装者は、プレースホルダーを表示用にエスケープ、翻訳してもよい。ユーザは事前にプレースホルダーの値をエスケープすべきではない。

プレースホルダーの例

/**
 * 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);

Context

  • 各メソッドは、配列をコンテキストデータとして受け取る
  • これはストリングでは表現できない補足情報を持たせることを意味します
  • 実装者はコンテキストデータを出来る限り寛大に扱わなければいけない
  • コンテキストデータによって、exceptionをthrowしたり、エラー、ワーニング等々を出してはいけない

  • もしExceptionオブジェクトがコンテキストデータで渡された時、それはexceptionキーの中になければいけない

  • exceptionのロギングは共通パターンにすることで、実装者はexceptionからスタックトレースを抽出することができます
  • 実装者はexceptionキーの値が実際にExceptionか検証しなければいけません

ヘルパークラスとインターフェース

  • Psr\Log\AbstractLoggerクラスを継承することで簡単にLoggerInterfaceと、汎用のlogを提供します
  • 同様にPsr\Log\LoggerTraitを使うことで実装がするのは汎用のlogメソッドだけです
  • しかしtraitsはインターフェースを実装せきないため、この場合はLoggerInterfaceを実装する必要があります
  • Psr\Log\NullLoggerはインターフェースと共に提供されます。これはユーザによってログがいらない場合にブラックホール用のインターフェースを提供します。しかしコンテキストデータの生成コストがかかる場合は条件付きロギングの方が良いです
  • Psr\Log\LoggerAwareInterfacesetLogger(LoggerInterface $logger)メソッドのみ含み、任意のインスタンスをロガーで接続するフレームワークで使用できます
  • Psr\Log\LoggerAwareTraitトレイトはどのクラスでも簡単に等価なインターフェースを提供します。$this->loggerでアクセスできます
  • Psr\Log\LogLevelは8個のログレベルを定数として持っています

色々composer経由で各種ライブラリを組み合わせて作るのが主流になっているので、その際個別にログ出力を実装しているとフォーマット、ディレクトリ等々バラけてしまいます。 またログレベルがバラバラだと環境別に出力の設定をしたい時個別にそれぞれしないといけません。

そこのインターフェース揃えれば、共通化できるし、差し替えも可能って感じかと!

PSR-4(Autoloader)へ続く・・・

PSR-4: Autoloader - PHP-FIG