CakePHP3でファイルログ出力をしたい

セキュリティのブログでログが大事という話をしました。

CakePHP3でのやり方を書いていきます。

当たり前の内容だからかわからないですが、やり方があまりネットで調べても出てこず、結構悩んだので書きたい内容でした。

【自分の環境】
macOS Catalina
PHP7.4.2
CakePHP3.8
MAMP5.7
Apache2.2
MySQL5.7

デフォルト設定の確認

たぶんデフォルトの内容でもデバッグログとエラーログは出ていると思います。

以下の内容でapp.phpに設定されているからです。

'Log' => [
        'debug' => [
            'className' => FileLog::class,
            'path' => LOGS,
            'file' => 'debug',
            'url' => env('LOG_DEBUG_URL', null),
            'scopes' => false,
            'levels' => ['notice', 'info', 'debug'],
        ],
        'error' => [
            'className' => FileLog::class,
            'path' => LOGS,
            'file' => 'error',
            'url' => env('LOG_ERROR_URL', null),
            'scopes' => false,
            'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'],
        ],
        // To enable this dedicated query log, you need set your datasource's log flag to true
        'queries' => [
            'className' => FileLog::class,
            'path' => LOGS,
            'file' => 'queries',
            'url' => env('LOG_QUERIES_URL', null),
            'scopes' => ['queriesLog'],
        ],
    ],

これで十分という方はそれでもOKです。

ただ自分の場合はアクセスログだけ取りたいっていう願望がありました。

そこでカスタムログ(custom.log)っていうログを出力させています。

名前が微妙ですが、気にしないでください。

新たなログファイルを作る

設定は以下です。

// エラーログの記述の下に以下を新しく追加
        'custom' => [
            'className' => FileLog::class,
            'path' => LOGS,
            'file' => 'custom',
            'levels' => ['notice', 'info'],
        ],

何てことない記述ですが、ポイントは2つです。

①fileをcustomにしている

これはcustom.logというファイルが新たに出来上がるようにするためです。

②levelsをnoticeとinfoだけにしている

levelsというのはログレベルのことです。

公式ドキュメントに一覧が載ってますが、深刻なものから軽微なものまで確か8種類くらいあります。

自己判断ですが、アクセスログの場合は失敗・成功でそれぞれnotice・infoにしようとしたので、この2つになっています。

ログ出力の記述をしていく

それではログ出力の記述をしていきます。

ここがあんまりネットになくて苦労しました。

①出力内容を書き換える、②ログ出力ポイントに書いていく、の2ステップです。

①出力内容を書き換える

これはファイルログの場合、/Applications/MAMP/htdocs/[アプリ名]/vendor/cakephp/cakephp/src/Log/Engineディレクトリの中にあるFileLog.phpをいじります。

かなり下層にあり、パスが長いですね…。

この中にあるlogファンクションをいじります。

自分の場合、以下のようになっています。

public function log($level, $message, array $context = [])
    {
        $message = $this->_format($message, $context);
        $output = date('Y-m-d H:i:s') . ' ' . ucfirst($level) . ': ' . $message . ' IPアドレス: ' . env('REMOTE_ADDR') .
                    ' アクセス対象URL: ' . env('REQUEST_URI') . ' リソースURL: ' . env('HTTP_REFERER') . "\n"; // 注目する行
        $filename = $this->_getFilename($level);
        if ($this->_size) {
            $this->_rotateFile($filename);
        }
      (中略)

注目する行と書いてある行を見てください。

変数outputをいろいろ書き加えています。

1つ1つ説明すると、

・date('Y-m-d H:i:s')…日時

・ucfirst($level)…エラーレベル

・$message…コントローラで記述できるメッセージ

・env('REMOTE_ADDR')…IPアドレス

・env('REQUEST_URI')…アクセス対象URL

・env('HTTP_REFERER')…アクセス元URL

以上になります。

これらがわかれば、だいぶアクセスしたユーザーの情報が分かります。

セキュリティのブログでお話した内容をほぼ網羅できています。

これで出力内容は定義できました。

②ログ出力ポイントに書いていく

残りはログ出力ポイントに書いていくだけです。

これはそのWebサービスによって異なってきますが、ログイン機能は大体あると思うので、そこを例に記述します。

loginアクションのあるコントローラに書いていきます。

以下のようになっています。

// ログイン処理
    function login(){
        // レイアウトを使わない
        $this->layout = '';
        
        // POST時の処理
        if($this->request->isPost()){
            $user = $this->Auth->identify();
            // Authのidentifyをユーザーに設定
            if(!empty($user)){
                $this->Auth->setUser($user);
                $this->log('ユーザーID' . $this->Auth->user()['id'] . 'によるログイン/成功', 'info'); // 注目する行
                return $this->redirect($this->Auth->redirectUrl());
            }
            $this->log('何者かによるログイン/失敗', 'notice'); // 注目する行
            $this->Flash->error('メールアドレスかパスワードが間違っています。');
        }
    }

また注目する行と書きました。

2つあります。

まずログイン成功のログです。

「$this->log('ユーザーID' . $this->Auth->user()['id'] . 'によるログイン/成功', 'info');」となっています。

ざっくり言うと、$this->log(メッセージ , ログレベル);というかんじです。

ユーザーIDを上手く引っ張れなかったので、自分はコントローラでメッセージとしていちいち記述しています。

また操作が成功したか失敗したかもメッセージで書いています。

そして成功の時はログレベルを「info」にしています。

逆に失敗に分岐した時は以下のログが出ます。

「$this->log('何者かによるログイン/失敗', 'notice');」です。

ここでもできればユーザーIDを取りたいですが、認証前なのでユーザーIDは取れません。

何者かが失敗して、noticeログを出そう、というかんじです。

これでcustom.logというファイルにアクセスログがズラズラっと出ているはずです。

場所は/Applications/MAMP/htdocs/[アプリ名]/logsに出ます。

終わりに

以上となります。

ログは結構奥が深いと思います。

まだ使いこなせてないですが、しっかり勉強して監視してこうと思います。

ありがとうございました。