CakePHP 3.8 で 404 Not Found エラーを別ログに保存する方法
はじめに
CakePHP 3 には標準でエラーログを保存する機能があり logs/debug.log や logs/error.log に保存されます。 これを監視することで不具合への早期対応も可能になります。
エラーログには 404 Not Found エラーも含まれます。Webサイトを公開すると phpmyadmin 等を狙った推測 URL へのアクセスが増えたりします。error.log にはそれも記載されるため、肥大化して必要な情報が見つけにくくなる場合があります。
そこで今日は CakePHP 3.8 で 404 Not Found エラーのログを別ファイルに保存する方法をご紹介します。
1. app.php にログ設定を追加
app.php の Log に 404 エラー用のログ設定を追加します。この例だと、ログは log/error_404.log に保存されます。
コード内の error404 の箇所は、アンダースコアを入れると正常に動作しませんでした。ハイフンは OK です。
'Log' => [
'error404' => [
'className' => FileLog::class,
'path' => LOGS,
'file' => 'error_404',
'url' => env('LOG_ERROR_URL', null),
'scopes' => ['error404'],
],
...
],
2. 独自の ErrorHandlerMiddleware を作成
下記内容で /src/Middleware/AppErrorHandlerMiddleware.php を作成します。
このコードは、404 扱いにしたい Exception をキャッチした際に、前述の app.php に追記した error404 の設定を使って、ログを保存する処理を行っています。
<?php
namespace App\Middleware;
use Cake\Error\Middleware\ErrorHandlerMiddleware;
use Cake\Log\Log;
class AppErrorHandlerMiddleware extends ErrorHandlerMiddleware
{
protected function logException($request, $exception)
{
// 404 扱いとする Exception
$targetExceptions = [
'Cake\Routing\Exception\MissingControllerException',
'Cake\Http\Exception\NotFoundException',
];
// 404 の場合は別ファイルにログを記述
if (in_array(get_class($exception), $targetExceptions)) {
$message = $this->getMessage($request, $exception);
Log::error($message, 'error404');
return;
}
parent::logException($request, $exception);
}
}
フォルダ構成は CakePHP 本体に合わせると src/Error/Middleware/ ですが、自作した Middleware は src/Middleware/ に置くべきみたいです。
- ミドルウェアの作成 (CakePHP 3 Cookbook)
- https://book.cakephp.org/3/ja/controllers/middleware.html#id6
3. Application.php で独自の Middleware 読み込み
Application.php で ErrorHandlerMiddleware の代わりに、作成した AppErrorHandlerMiddleware を使用するようにします。
<?php
namespace App;
use App\Middleware\AppErrorHandlerMiddleware; // ← 追記
...
// use Cake\Error\Middleware\ErrorHandlerMiddleware; // ← コメントアウト or 削除
...
public function middleware($middlewareQueue)
{
$middlewareQueue
// ->add(new ErrorHandlerMiddleware(null, Configure::read('Error'))) // ←コメントアウト or 削除
->add(new AppErrorHandlerMiddleware(null, Configure::read('Error'))) // ←追記
...
}
...
4. ログ記載内容の変更
404 エラーにはトレース結果を残さなくてもよい、というような場合には、下記のように AppErrorHandlerMiddleware.php の $message を任意のものに変更すれば OK です。
// 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}";
Log::error($message, 'error404');
return;
}
5. おわりに
404 エラーを別ファイルに残すと error.log がすっきりします。またログ記載内容を必要なものだけにすれば、さらに保守性がよくなります。ログを使いやすく残すことは大切なので、必要に応じて CakePHP のログ機能をカスタムすると良いと思います。