CakePHP 4.0 で 404 Not Found エラーを別ログに保存する方法
はじめに
CakePHP 4 にはエラーログを保存する機能があり、不具合の早期発見に役立ちます。エラーログは logs/error.log に保存されますが、この中には 404 Not Found エラーも含まれます。
Web サイトを公開すると wordpress や phpmyadmin などを狙った URL へのアクセスもあり、これらが error.log に貯まってしまうと必要な情報が見つけにくくなります。
そこで今日は CakePHP 4.0 で 404 Not Found エラーのログを別ファイルに保存する方法を、ログ内容の変更方法と併せてご紹介します。
昨年末に CakePHP 3.8 での方法をご紹介しましたが、CakePHP 4 はエラー周りのコードに変更が加えられており、手順が異なるのでご注意ください。
1. app.php に設定追加
CakePHP 4.0 では、エラーログへの書込処理は /vendor/cakephp/cakephp/src/Error/ErrorLogger.php の log() 関数で行っています。
今回はこの ErrorLogger クラスを継承した、独自の AppErrorLogger クラスを作成して log() 関数をつくり、そこに 404 Not Found の場合は別ファイルにログを残す処理を書きます。
ErrorLogger の指定は config/app.php で下記のように行います。また 404 Not Found 用ログファイル(logs/error_404.log)の設定も追記します。
<?php
use App\Error\AppErrorLogger; // ←追加
...
return [
...
'Error' => [
...
'errorLogger' => AppErrorLogger::class, // ← 追加
],
...
'Log' => [
// 以下を追加
'error404' => [
'className' => FileLog::class,
'path' => LOGS,
'file' => 'error_404',
'url' => env('LOG_ERROR_URL', null),
'scopes' => ['error404'],
],
...
errorLogger オプションは初期状態の app.php にはなく、公式ドキュメントで見つけました。
- Error & Exception Handling (CakePHP 4 Cookbook)
- https://book.cakephp.org/4/en/development/errors.html#error-exception-configuration
2. 独自の ErrorLogger を作成
下記内容で /src/Error/AppErrorLogger.php を作成します。
MissingControllerException が CakePHP 3 と異なっているので注意です。
<?php
declare(strict_types=1);
namespace App\Error;
use Cake\Error\ErrorLogger;
use Cake\Log\Log;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;
class AppErrorLogger extends ErrorLogger
{
public function log(Throwable $exception, ?ServerRequestInterface $request = null): bool
{
// 404 扱いとする Exception
$targetExceptions = [
'Cake\Controller\Exception\MissingActionException',
'Cake\Http\Exception\MissingControllerException',
'Cake\Http\Exception\NotFoundException',
];
// 404 の場合は別ファイルにログを記述
if (in_array(get_class($exception), $targetExceptions)) {
$message = $this->getMessage($exception);
if ($request !== null) {
$message .= $this->getRequestContext($request);
}
$message .= "\n\n";
return Log::error($message, ['scope' => 'error404']);
}
return parent::log($exception, $request);
}
}
以上で完了です。あとは存在しないアクションにアクセスしたり、NotFoundException を発生させて動作を確認してください。
3. ログ記載内容の変更
ログ内容を変更したい場合は、log() 関数の $message の箇所を下記のように変更してください。
// 404 の場合は別ファイルにログを記述
if (in_array(get_class($exception), $targetExceptions)) {
// 独自のログ内容
$url = $_SERVER['REQUEST_URI'];
$ip = $_SERVER['REMOTE_ADDR'];
$ua = $_SERVER['HTTP_USER_AGENT'];
$message = "{$url}\t{$ip}\t{$ua}";
return Log::error($message, ['scope' => 'error404']);
}
4. おわりに
CakePHP 4.0 は 3.0 に似ていて、比較的多くのコードを流用できていますが、エラーログ周りのロジックには変更があり、今回ご紹介したログ分割は実装方法が大きく異なりました。
まだ CakePHP 4.0 の資料が少ないため、今回は本体のコードを分析して実装しました。独自の ErrorMiddleware と ErrorHandler の組み合わせも考えたのですが、今のところは上記の AppErrorLogger で行うのが一番簡潔かなと考えています。