CakePHP 4.4 で Not Found 系エラーを別ログに保存する方法

はじめに

以前 「CakePHP 4.0 で 404 Not Found エラーを別ログに保存する方法」 を投稿しましたが、CakePHP 4.4.0 から仕様が変わり、実装方法にも少し違いがあります。

今日は CakePHP 4.4 で 404 系エラーログを別ファイルに保存する方法をご紹介します。

目次
  1. 実装方法
  2. ログ出力内容の変更
  3. おわりに

1. 実装方法

まず config/app.php に下記のように追記します。

config/app.php
<?php
use App\Error\AppErrorLogger; // ←追加
...
return [
    ...
    'Error' => [
        ...
        'logger' => AppErrorLogger::class, // ← 追加
    ],
    ...
    'Log' => [
        // 以下を追加
        'error404' => [
            'className' => FileLog::class,
            'path' => LOGS,
            'file' => 'error_404',
            'url' => env('LOG_ERROR_URL', null),
            'scopes' => ['notFound'],
        ],
        ...

そして src/Error/AppErrorLogger.php を作成します。

src/Error/AppErrorLogger.php
<?php
declare(strict_types=1);

namespace App\Error;

use Cake\Error\ErrorLogger;
use Cake\Log\Log;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

/**
 * Application ErrorLogger
 */
class AppErrorLogger extends ErrorLogger
{
    /**
     * @inheritDoc
     */
    public function logException(
        Throwable $exception,
        ?ServerRequestInterface $request = null,
        bool $includeTrace = false
    ): void {
        // 404 扱いとする Exception
        $targetExceptions = [
            'Cake\Controller\Exception\MissingActionException',
            'Cake\Datasource\Exception\RecordNotFoundException',
            'Cake\Http\Exception\MissingControllerException',
            'Cake\Http\Exception\NotFoundException',
            'Cake\Routing\Exception\MissingRouteException',
        ];

        // 404 エラーの場合は config/app.php に追加した error404 の設定を使用
        $expClass = get_class($exception);
        $is404 = in_array($expClass, $targetExceptions);
        $context = $is404 ? ['scope' => 'notFound'] : [];

        // ログに記載する内容を取得
        $message = $this->getMessage($exception, false, $includeTrace);
        if ($request !== null) {
            $message .= $this->getRequestContext($request);
        }

        Log::error($message, $context);
    }
}

以上で実装は終わりです。

あとは存在しない URL にアクセスしたりして、動作確認をしてみてください。
問題がなければ logs/error_404.log に出力されます。

2. ログ出力内容の変更

error_404.log に出力する内容を変更したい場合には、AppErrorLogger.php を下記のように変更すれば OK です。

src/Error/AppErrorLogger.php
// ログに記載する内容を取得 (以下を変更)
if ($is404) {
    $url = $_SERVER['REQUEST_URI'];
    $ip = $_SERVER['REMOTE_ADDR'];
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
    $message = "{$url}\t{$expClass}\t{$ip}\t{$ua}";
} else {
    $message = $this->getMessage($exception, false, $includeTrace);
    if ($request !== null) {
        $message .= $this->getRequestContext($request);
    }
}

3. おわりに

執筆時点では、下記日本語ドキュメントには 4.4 の更新情報が反映されていません。

日本語ドキュメント通りにやってうまくいかないときは、英語版を参照することをお勧めします。

今回のように最新バージョンが反映されていない場合は 「prior to」 という英単語がキーワードの一つになるかと思います。