Yii は、高度にカスタマイズ可能で拡張性の高い強力なロギングフレームワークを提供します。このフレームワークを使用すると、さまざまなタイプのメッセージを簡単にログに記録し、フィルタリングし、ファイル、データベース、メールなど、さまざまなターゲットに収集できます。
Yii ロギングフレームワークの使用には、次の手順が含まれます。
このセクションでは、主に最初の 2 つの手順について説明します。
ログメッセージの記録は、次のロギングメソッドのいずれかを呼び出すほど簡単です。
これらのロギングメソッドは、さまざまな重大度レベルとカテゴリでログメッセージを記録します。それらは同じ関数シグネチャ `function ($message, $category = 'application')` を共有します。ここで、`$message` は記録されるログメッセージを表し、`$category` はログメッセージのカテゴリです。次の例のコードは、デフォルトのカテゴリ `application` でトレースメッセージを記録します。
Yii::debug('start calculating average revenue');
情報:ログメッセージは文字列だけでなく、配列やオブジェクトなどの複雑なデータでもかまいません。ログターゲットは、ログメッセージを適切に処理する責任があります。デフォルトでは、ログメッセージが文字列でない場合、yii\helpers\VarDumper::export() を呼び出すことによって文字列としてエクスポートされます。
ログメッセージの整理とフィルタリングを効果的に行うために、各ログメッセージに適切なカテゴリを指定することをお勧めします。カテゴリには階層的な命名スキームを使用できます。これにより、ログターゲットがカテゴリに基づいてメッセージをフィルタリングしやすくなります。シンプルながらも効果的な命名スキームとしては、カテゴリ名にPHPのマジック定数__METHOD__
を使用する方法があります。これはYiiフレームワークのコアコードでも使用されているアプローチです。例:
Yii::debug('start calculating average revenue', __METHOD__);
__METHOD__
定数は、定数が出現するメソッド名(完全修飾クラス名で接頭辞が付けられる)として評価されます。たとえば、上記のコード行がメソッド内で呼び出された場合、文字列'app\controllers\RevenueController::calculate'
と等しくなります。
情報:上記で説明されているログメソッドは、実際にはlog()メソッドへのショートカットです。loggerオブジェクトはシングルトンであり、
Yii::getLogger()
という式でアクセスできます。十分な数のメッセージがログに記録された場合、またはアプリケーションが終了した場合、loggerオブジェクトはメッセージディスパッチャを呼び出して、登録済みのログターゲットに記録されたログメッセージを送信します。
ログターゲットは、yii\log\Targetクラスまたはその子クラスのインスタンスです。ログメッセージを重大度レベルとカテゴリでフィルタリングし、特定の媒体に出力します。たとえば、データベースターゲットはフィルタリングされたログメッセージをデータベーステーブルに出力し、メールターゲットはログメッセージを指定されたメールアドレスに出力します。
アプリケーション構成のlog
アプリケーションコンポーネントを介して、複数のログターゲットをアプリケーションに登録できます。以下に例を示します。
return [
// the "log" component must be loaded during bootstrapping time
'bootstrap' => ['log'],
// the "log" component process messages with timestamp. Set PHP timezone to create correct timestamp
'timeZone' => 'America/Los_Angeles',
'components' => [
'log' => [
'targets' => [
[
'class' => 'yii\log\DbTarget',
'levels' => ['error', 'warning'],
],
[
'class' => 'yii\log\EmailTarget',
'levels' => ['error'],
'categories' => ['yii\db\*'],
'message' => [
'from' => ['log@example.com'],
'to' => ['admin@example.com', 'developer@example.com'],
'subject' => 'Database errors at example.com',
],
],
],
],
],
];
注意:
log
コンポーネントは、ブートストラップ時にロードする必要があります。これにより、ターゲットにログメッセージを迅速にディスパッチできます。そのため、上記のようにbootstrap
配列にリストされています。
上記のコードでは、yii\log\Dispatcher::$targetsプロパティに2つのログターゲットが登録されています。
yii\db\
で始まるカテゴリのエラーメッセージを選択し、admin@example.com
とdeveloper@example.com
の両方にメールで送信します。Yiiには、以下の組み込みログターゲットがあります。これらのクラスに関するAPIドキュメントを参照して、設定方法と使用方法を確認してください。
syslog()
を呼び出して、ログメッセージをsyslogに保存します。次に、すべてのログターゲットに共通する機能について説明します。
各ログターゲットについて、そのlevelsプロパティとcategoriesプロパティを設定して、ターゲットが処理するメッセージの重大度レベルとカテゴリを指定できます。
levelsプロパティには、以下の値の1つまたは複数を含む配列が設定されます。
error
:Yii::error()によってログに記録されたメッセージに対応します。warning
:Yii::warning()によってログに記録されたメッセージに対応します。info
:Yii::info()によってログに記録されたメッセージに対応します。trace
:Yii::debug()によってログに記録されたメッセージに対応します。profile
:Yii::beginProfile()とYii::endProfile()によってログに記録されたメッセージに対応します。これはプロファイリングのサブセクションで詳しく説明します。levelsプロパティを指定しない場合、ターゲットは任意の重大度レベルのメッセージを処理します。
categoriesプロパティには、メッセージカテゴリ名またはパターンの配列が設定されます。ターゲットは、そのカテゴリがこの配列のいずれかのパターンに一致するメッセージのみを処理します。カテゴリパターンは、最後にアスタリスク*
が付いたカテゴリ名です。カテゴリ名は、パターンのプレフィックスと同じで始まる場合、カテゴリパターンと一致します。たとえば、yii\db\Commandクラスで記録されたログメッセージのカテゴリ名として、yii\db\Command::execute
とyii\db\Command::query
が使用されます。これらは両方ともパターンyii\db\*
と一致します。
categoriesプロパティを指定しない場合、ターゲットは任意のカテゴリのメッセージを処理します。
categoriesプロパティを使用して許可されるカテゴリを指定することに加えて、exceptプロパティを使用して特定のカテゴリを除外することもできます。メッセージのカテゴリがこのプロパティのいずれかのパターンと一致する場合、ターゲットによって処理されません。
次のターゲット構成は、ターゲットがyii\db\*
またはyii\web\HttpException:*
と一致するカテゴリのエラーと警告メッセージのみを処理し、yii\web\HttpException:404
は処理しないことを指定しています。
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
'categories' => [
'yii\db\*',
'yii\web\HttpException:*',
],
'except' => [
'yii\web\HttpException:404',
],
]
情報:エラーハンドラによってHTTP例外がキャッチされると、
yii\web\HttpException:ErrorCode
形式のカテゴリ名でエラーメッセージがログに記録されます。たとえば、yii\web\NotFoundHttpExceptionは、カテゴリyii\web\HttpException:404
のエラーメッセージを発生させます。
ログターゲットは、フィルタリングされたログメッセージを特定のフォーマットで出力します。たとえば、yii\log\FileTargetクラスのログターゲットをインストールすると、runtime/log/app.log
ファイルに次のようなログメッセージが表示される場合があります。
2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug
デフォルトでは、ログメッセージはyii\log\Target::formatMessage()によって以下のようにフォーマットされます。
Timestamp [IP address][User ID][Session ID][Severity Level][Category] Message Text
カスタマイズされたメッセージプレフィックスを返すPHPのcallableを設定することで、yii\log\Target::$prefixプロパティを構成してこのフォーマットをカスタマイズできます。たとえば、次のコードは、各ログメッセージに現在のユーザーIDをプレフィックスとして付けるようにログターゲットを設定します(プライバシーの理由から、IPアドレスとセッションIDは削除されています)。
[
'class' => 'yii\log\FileTarget',
'prefix' => function ($message) {
$user = Yii::$app->has('user', true) ? Yii::$app->get('user') : null;
$userID = $user ? $user->getId(false) : '-';
return "[$userID]";
}
]
メッセージプレフィックスに加えて、ログターゲットは各ログメッセージのバッチにいくつかのコンテキスト情報を追加します。デフォルトでは、これらのグローバルPHP変数の値が含まれます:$_GET
、$_POST
、$_FILES
、$_COOKIE
、$_SESSION
、$_SERVER
。 yii\log\Target::$logVarsプロパティを構成して、ログターゲットに含めるグローバル変数の名前を指定することで、この動作を調整できます。たとえば、次のログターゲット構成では、$_SERVER
変数の値のみがログメッセージに追加されます。
[
'class' => 'yii\log\FileTarget',
'logVars' => ['_SERVER'],
]
コンテキスト情報の包含を完全に無効にするには、logVars
を空の配列に設定します。または、コンテキスト情報の提供方法を独自に実装する場合は、yii\log\Target::getContextMessage()メソッドをオーバーライドできます。
リクエストフィールドの一部にログに記録したくない機密情報(パスワード、アクセストークンなど)が含まれている場合、maskVars
プロパティを追加で構成できます。デフォルトでは、以下のリクエストパラメータは***
でマスクされます:$_SERVER[HTTP_AUTHORIZATION]
、$_SERVER[PHP_AUTH_USER]
、$_SERVER[PHP_AUTH_PW]
ですが、独自に設定できます。
[
'class' => 'yii\log\FileTarget',
'logVars' => ['_SERVER'],
'maskVars' => ['_SERVER.HTTP_X_PASSWORD']
]
開発中は、各ログメッセージの出所を確認することがよくあります。これは、次のようにlog
コンポーネントのtraceLevelプロパティを構成することで実現できます。
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [...],
],
],
];
上記のアプリケーション構成では、YII_DEBUG
がオンの場合はtraceLevelを3に、YII_DEBUG
がオフの場合は0に設定しています。つまり、YII_DEBUG
がオンの場合、各ログメッセージには、ログメッセージが記録されたコールスタックの最大3レベルが追加され、YII_DEBUG
がオフの場合は、コールスタック情報は含まれません。
情報:コールスタック情報の取得は容易ではありません。そのため、この機能は開発中またはアプリケーションのデバッグ時のみ使用するようにしてください。
前述のように、ログメッセージはloggerオブジェクトによって配列に保持されます。この配列によるメモリ消費を制限するために、loggerは、配列に特定数のログメッセージが蓄積されるたびに、記録されたメッセージをログターゲットにフラッシュします。この数は、log
コンポーネントのflushIntervalプロパティを構成することでカスタマイズできます。
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'flushInterval' => 100, // default is 1000
'targets' => [...],
],
],
];
情報:アプリケーションが終了したときにもメッセージのフラッシュが行われます。これにより、ログターゲットは完全なログメッセージを受信できます。
loggerオブジェクトがログメッセージをログターゲットにフラッシュしても、すぐにエクスポートされるわけではありません。代わりに、メッセージのエクスポートは、ログターゲットがフィルタリングされたメッセージの特定の数を蓄積した場合にのみ行われます。この数は、個々のログターゲットのexportIntervalプロパティを構成することでカスタマイズできます。以下に例を示します。
[
'class' => 'yii\log\FileTarget',
'exportInterval' => 100, // default is 1000
]
フラッシュとエクスポートレベルの設定のため、デフォルトでは、Yii::debug()
またはその他のログメソッドを呼び出しても、ログターゲットにログメッセージがすぐに表示されるわけではありません。これは、長時間実行されるコンソールアプリケーションでは問題になる可能性があります。各ログメッセージをログターゲットにすぐに表示するには、以下のようにflushIntervalとexportIntervalの両方を1に設定する必要があります。
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'flushInterval' => 1,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'exportInterval' => 1,
],
],
],
],
];
注意:頻繁なメッセージのフラッシュとエクスポートは、アプリケーションのパフォーマンスを低下させます。
ログターゲットのenabledプロパティを構成することで、ログターゲットを有効または無効にできます。ログターゲット構成を介して、またはコード内の次のPHPステートメントを使用して実行できます。
Yii::$app->log->targets['file']->enabled = false;
上記のコードでは、targets
配列で文字列キーを使用することによって、以下のようにターゲットにfile
という名前を付ける必要があります。
return [
'bootstrap' => ['log'],
'components' => [
'log' => [
'targets' => [
'file' => [
'class' => 'yii\log\FileTarget',
],
'db' => [
'class' => 'yii\log\DbTarget',
],
],
],
],
];
バージョン2.0.13以降、enabledをcallableで構成して、ログターゲットを有効にするかどうかの動的な条件を定義できます。yii\log\Target::setEnabled()のドキュメントを参照して例を確認してください。
新しいログターゲットクラスの作成は非常に簡単です。yii\log\Target::$messages配列の内容を指定された媒体に送信するyii\log\Target::export()メソッドを実装する必要があります。yii\log\Target::formatMessage()メソッドを呼び出して、各メッセージをフォーマットできます。詳細については、Yiiリリースに含まれるログターゲットクラスのいずれかを参照してください。
ヒント:独自のloggerを作成する代わりに、PSRログターゲット拡張を使用して、MonologなどのPSR-3互換のloggerを試すことができます。
パフォーマンスプロファイリングは、特定のコードブロックの実行時間を測定し、パフォーマンスボトルネックを特定するために使用される特殊なメッセージロギングです。例えば、yii\db\Commandクラスは、各DBクエリの実行時間を調べるためにパフォーマンスプロファイリングを使用しています。
パフォーマンスプロファイリングを使用するには、最初にプロファイリングする必要があるコードブロックを特定します。次に、各コードブロックを以下のように囲みます。
\Yii::beginProfile('myBenchmark');
...code block being profiled...
\Yii::endProfile('myBenchmark');
ここで、myBenchmark
はコードブロックを一意に識別するトークンを表します。後でプロファイリング結果を調べるときに、このトークンを使用して、対応するコードブロックで費やされた時間を特定します。
beginProfile
とendProfile
のペアが適切にネストされていることを確認することが重要です。例えば、
\Yii::beginProfile('block1');
// some code to be profiled
\Yii::beginProfile('block2');
// some other code to be profiled
\Yii::endProfile('block2');
\Yii::endProfile('block1');
\Yii::endProfile('block1')
が欠落していたり、\Yii::endProfile('block1')
と\Yii::endProfile('block2')
の順序が入れ替わっていたりすると、パフォーマンスプロファイリングは機能しません。
プロファイリングされる各コードブロックに対して、重大度レベルprofile
のログメッセージが記録されます。そのようなメッセージを収集してエクスポートするために、ログターゲット を設定できます。Yiiデバッガーには、プロファイリング結果を表示する組み込みのパフォーマンスプロファイリングパネルがあります。
タイプミスを発見した、またはこのページの改善が必要だと考えますか?
Githubで編集する !
コメントするにはサインアップまたはログインしてください。