RitoLabo

【PHP】PSR-3 Logger Interface(ロガーインタフェース)

  • 公開:
  • 更新:
  • カテゴリ: PHP PSR
  • タグ: PHP,PSR,PSR-3,Log

PSR-3では、PHPにおけるロギングライブラリの共通インタフェースについて定義されています。

ライブラリが Psr\Log\LoggerInterface オブジェクトを受け取り、ログを簡単で共通化された方法で書き込むことができるようにすることが、このドキュメントの目的です。

フレームワークやCMSを拡張する際もPSR-3に準拠することによって、ログライブラリはロギングに集中する事が出来ます。

尚、このドキュメントに登場する実装者とは、ロギングの仕組み自体を実装する人の事を、ユーザーとは、開発の中でそのロギングライブラリを利用する人の事を指しています。

目次
  1. 仕様
    1. 基本
      1. log()メソッド
    2. メッセージ
      1. メッセージ処理
      2. メッセージ内プレースホルダの書式
    3. コンテキスト
      1. コンテキストの定義と処理方針
      2. 例外
    4. ヘルパークラスとインタフェース
      1. AbstractLogger
      2. LoggerTrait
      3. NullLogger
      4. LoggerAwareInterface
      5. LoggerAwareTrait
      6. LogLevel
  2. パッケージ
  3. Psr\Log\LoggerInterface
  4. Psr\Log\LoggerAwareInterface
  5. Psr\Log\LogLevel

仕様

このセクションは、ロギングライブラリの基本的な仕様について定義されています。

基本

LoggerInterfaceは、ログを以下8つのRFC 5424(Syslog Protocol)レベルに書き込む、8つのメソッドを公開します。

  • デバッグ
  • 情報
  • 通知
  • 警告
  • エラー
  • クリティカル
  • アラート
  • 緊急
Syslog
ログメッセージをIPネットワーク上で転送するための標準規格。
RFC 5424
イベント通知メッセージを伝えるために使用されるsyslogプロトコルについて定義されています。
標準としてのSyslog設計目標を念頭に置いて書かれており、これまで(RFC3164)では、より信頼性と安全性の高いsyslog拡張の標準化のためにStandards-TrackとTransport-independent RFCが欠けている(お互いの標準で独自のsyslogパケットフォーマットと転送メカニズムを定義する必要があり、時間が経つにつれてわずかな互換性の問題が生じる)ため、新たな階層化仕様としてRFC5424が策定されました。
RFC5424では、Syslogの階層化されたアーキテクチャについて説明しています。このアーキテクチャの目的は、メッセージコンテンツとメッセージトランスポートを分離し、各レイヤーの容易な拡張を可能にすることです。

log()メソッド

ログライブラリを繋げる「9番目のメソッド」として位置づける。log()メソッドでログレベルの定数(const)を渡すことでロギングを行うイメージ。

  • log()メソッドは最初の引数としてログレベルを受け取る。
  • ログレベル定数の1つでこのメソッドを呼び出せば、必ずレベル固有のメソッドが呼び出され、必ず同じ結果が返されなければならない。
  • もしこの仕様で定義されていないレベルでこのメソッドを呼び出した場合は、Psr\Log\InvalidArgumentExceptionをスローする。
  • カスタムレベルを使う場合は、それ自体が定義されているかをまず確認する。

メッセージ

ログメッセージには固定としてのテキストだけでなく、内容によって状況独自の値を入れる場合がありますが、その際の一連の処理について定義されています。

メッセージ処理

すべてのメソッドは文字列をメッセージとして受け取るか、__toString()メソッドを持つオブジェクトを受け取る。そうでないものが入ってきた場合はそれを文字列にキャストする。そして実装者は渡されたオブジェクトに対して処理を行うことができる。

メッセージ内プレースホルダの書式

メッセージには、実装者がコンテキスト配列からの値で置き換えることができるプレースホルダが含まれるかもしれません。

  • プレースホルダ名は、コンテキスト配列内のキーに対応させる。
  • プレースホルダ名は、単一の開始波括弧 { と単一の閉じ波括弧 } で区切る。
  • 区切り文字とプレースホルダ名の間に空白は入れない。
  • プレースホルダ名は、文字A-Z/a-z/0-9/アンダースコア_/ピリオド. のみで構成する。(他の文字の使用は、プレースホルダ仕様の将来の変更のために予約される。)

実装者はプレースホルダを使用してさまざまなエスケープ処理を実装し、表示用にログを構築することができます。

ユーザは、データがどのコンテキストで表示されるかを知ることができないため、プレースホルダ値を事前にエスケープしてはいけません。

以下は、参照目的でのみ提供されるプレースホルダ補間の実装例です。

<?php

/**
* メッセージプレースホルダにコンテキスト値を補間する。
*/
function interpolate($message, array $context = array())
{
// コンテクストキーの周りに中カッコを入れた置換配列を作成する
$replace = array();
foreach ($context as $key => $val) {
// 値を文字列にキャストできることを確認する
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
$replace['{' . $key . '}'] = $val;
}
}

// 置換値をメッセージに補間して戻す
return strtr($message, $replace);
}

// 中括弧で区切られたプレースホルダ名を含むメッセージ
$message = "User {username} created";

// プレースホルダ名のコンテキスト配列=>置換値
$context = array('username' => 'rito');

// メッセージと補完値をエコーする
echo interpolate($message, $context);

コンテキスト

ここでのコンテキストとは、固定されない、状況によって渡される情報の事。プレースホルダと置き換えられる対象の値になります。

コンテキストの定義と処理方針

すべてのメソッドは、配列をコンテキストデータとして受け取ります。そしてその配列は、固定メッセージに対してその状況により補完すべき情報(文字列)を保持するための配列です。

配列にはいくつでも情報を含めることができます。故に実装者は、柔軟かつ寛大に文脈データを扱う必要があります。

例えばコンテキスト内の指定された値に対して、例外をスローしたり、PHPエラー、警告または通知を出してはいけません。つまり、確実に処理しろ。という事です。

例外

Exceptionオブジェクトがコンテキストデータに渡される場合、例外オブジェクトは exceptionキーに含まれている必要があります。

ロギング例外は共通のパターンであり、これにより実装者はログバックエンドがサポートするときに、例外からスタックトレースを抽出することができます。

実装者は、「例外」キーが何かを含む可能性があるので、それを使用する前に、実際に例外キーが実際に例外であることを確認しなければなりません。

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

以下は、ヘルパークラスとインタフェースについての説明です。

AbstractLogger

Psr\Log\AbstractLoggerクラスを使用すると、LoggerInterfaceを拡張して汎用ログメソッドを実装することで、LoggerInterfaceを非常に簡単に実装できます。

他の8つの方法は、メッセージとコンテキストをそれに転送しています。

LoggerTrait

AbstractLoggerクラスと同様に、Psr\Log\LoggerTraitを使用する場合は汎用ログメソッドを実装する必要があります。

Traitはインタフェースを実装できないため、この場合でもLoggerInterfaceを実装する必要があります。
[php.net]トレイト
http://php.net/manual/ja/language.oop5.traits.php

NullLogger

Psr\Log\NullLogger は、インターフェイスと共に提供されます。これは、ロガーが与えられていなければ、インターフェースのユーザーがフォールバックの実装を提供するために使用することができます。しかし、コンテキスト・データの作成が難しい場合は、条件付きロギングがより良いアプローチになります。

LoggerAwareInterface

Psr\Log\LoggerAwareInterface には setLogger(LoggerInterface $logger)メソッドのみが含まれており、任意のインスタンスをロガーで自動配線するためにフレームワークで使用できます。

LoggerAwareTrait

Psr\Log\LoggerAwareTrait は、どのクラスでも同等のインターフェースを簡単に実装するために使用できます。 $this->loggerでアクセスできます。

LogLevel

Psr\Log\LogLevelクラスは、8つのログレベルの定数を保持します。

パッケージ

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

Psr\Log\LoggerInterface

ロガーインスタンスのインターフェイス

<?php

namespace Psr\Log;

/**
* ロガーインスタンスのインターフェイス
*
* メッセージは、__toString()を実装している文字列またはオブジェクトでなければなりません。
*
* メッセージは{foo}の形式でプレースホルダを含むかもしれません。
* ここでfooはキー "foo"のコンテキストデータに置き換えられます。
*
* コンテキスト配列は任意のデータを含むことができます。実装者が行うことができる唯一の仮定は、
* Exceptionインスタンスがスタックトレースを生成するために与えられた場合、
* "exception"という名前のキーになければならないということです。
*
* interfaceの全ての仕様
* https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
*
*/
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.
*
* 例:ウェブサイト全体がダウンし、データベースが利用できないなど。
*   SMSアラートなどで通知するレベルです。
*
* @param string $message
* @param array $context
* @return void
*/
public function alert($message, array $context = array());

/**
* Critical conditions.
*
* 例:アプリケーションコンポーネントが使用できない、予期しない例外。
*
* @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.
* エラーではない例外的な発生。
*
* 例:廃止予定のAPIの使用、APIの使い方の悪さなど、必ずしも間違っていないが望ましくないもの。
*
* @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());
}

Psr\Log\LoggerAwareInterface

ロガーセットインスタンスのインターフェイス

<?php

namespace Psr\Log;

/**
* ロガーセットインスタンスのインターフェイス
*/
interface LoggerAwareInterface
{
/**
* オブジェクト上にロガーインスタンスを設定する。
*
* @param LoggerInterface $logger
* @return void
*/
public function setLogger(LoggerInterface $logger);
}

Psr\Log\LogLevel

ログレベル定数

<?php

namespace Psr\Log;

/**
* ログレベル定数
*/
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';
}