CakePHP2 ログローテーションの重複実行の回避

事情によりCakePHP2を使っているのですが、アクセスが増えた時に、レスポンス遅延が発生しました。 どうも警告が大量に出力されたり、そもそもログ出力が多かったりして、ログローテーションが重複実行されて サーバが不安定になったことがあり、CakePHP2のファイルログのソースコード(lib/Cake/Log/Engine/FileLog.php)を見たところ、 ログ出力メソッド内で、ファイルサイズをチェックして、renameしたりunlinkしていくという、かなり愚直な実装になっていました。 そして、重複実行をブロックするような処理はありませんでした。 CakePHP2を使ってPVが多いサイトを運用してきた人達もいっぱいいると思うんですが、大丈夫なんですかね?問題なかったんだろうか。

CakePHP2のFileLogを拡張して、ログローテーションにロック機能を付けてみました。

app/Log/Engine/AppFileLog.php

Cakeのソースである FileLog.php の _rotateFile メソッドをオーバーライドすることでログローテーションにロック機能を 付けてみました。

<?php
App::uses('FileLog', 'Log/Engine');
 class AppFileLog extends FileLog {/**
     * ローテイトする必要があればローテイトを行なうメソッド
     *
     * ローテイトにロック機能を付与して、重複してローテイト処理が行なわれるのを回避します。
     * ログディレクトリに、ロックファイル(rotate.lockディレクトリ)を作成することでロックします。
     * 10分以上前に作成されたロックファイルは、期限切れとして削除します。
     *
     * @param string $filename Log file name
     * @return mixed True if rotated successfully or false in case of error, otherwise null.
     *   Void if file doesn't need to be rotated.
     */protected function _rotateFile($filename) {$filepath = $this->_path . $filename;if (version_compare(PHP_VERSION, '5.3.0') >= 0) {clearstatcache(true, $filepath);} else {clearstatcache();}
  if (!file_exists($filepath) ||filesize($filepath) < $this->_size ) {return null;}
  //ローテイトロックの確認$rotate_lock = sprintf('%s/rotate.lock', $this->_path);$rotating = file_exists($rotate_lock);if ($rotating) {$expire = strtotime('10 minutes ago');$created = filemtime($rotate_lock);if ($created < $expire){rmdir($rotate_lock); //10分前のロックファイルは既に期限切れとして削除する。$rotating = false;//ロック解除する。}}if ($rotating) {//ローテイト中なら終了する。重複して処理しない。return;}//ロックファイル作成mkdir($rotate_lock);
  if ($this->_config['rotate'] === 0) {$result = unlink($filepath);} else {$result = rename($filepath, $filepath . '.' . time());}
  $files = glob($filepath . '.*');if ($files) {$filesToDelete = count($files) - $this->_config['rotate'];while ($filesToDelete > 0) {unlink(array_shift($files));$filesToDelete--;}}
  rmdir($rotate_lock); //ロックファイルを削除する。return $result;}}

app/Config/bootstrap.php

bootstrap.php で、engine に AppFile を指定することで、追加した AppFileLog.php を使うようにしています。

<?php
CakeLog::config('debug', array('engine' => 'AppFile','types' => array('notice', 'info', 'debug'),'file' => 'debug' . '_' . date('Ymd'),));
CakeLog::config('error', array('engine' => 'AppFile','types' => array('warning', 'error', 'critical', 'alert', 'emergency'),'file' => 'error' . '_' . date('Ymd'),));

新しいシステムなら、ログはfluentdとかに纏めるんだろうなぁ。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


reCaptcha の認証期間が終了しました。ページを再読み込みしてください。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください