Help us understand the problem. What is going on with this article?

CodeIgniterのログを独自カテゴリーに分けて出力する

More than 1 year has passed since last update.

CodeIgniterにはログファイルを簡単に作成してくれる関数が用意されています。

エラー処理-log_message
http://codeigniter.jp/user_guide/3/general/errors.html?highlight=%E3%83%AD%E3%82%B0#log_message

この関数、CodeIgniterが読み込まれている範囲であればどこでも、

log_message('debug', 'デバックメッセージ');

と書けば、application/logsの中にlog-2018-10-05.phpのような形でファイルが作成され、中身に

log-2018-10-05.php
<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>

DEBUG - 2018-10-05 17:33:35 --> デバックメッセージ

というようなログが溜まっていきます(ただし、config/config.phpの設定やapplication/logsへApacheの書き込み権限設定が必要)。

しかしこのログ、自分で仕込んだlog_message()以外にもCodeIgniterのコア部分で多用されていることもあり、CodeIgniterが起動する度に結構なメッセージが書き込まれていきます。

時系列に沿って書き込まれていくとはいえ、欲を言えばカテゴリー別にログが取れればもっと便利にログを使えそうです。

なので作りました。

※対象はCodeIgniterの3系です。

Logクラスを拡張する

コアシステムクラスの作成-システムクラス一覧

だいたいのCodeIgniterのコアクラスは自作のクラスで代替可能です。

ただし公式マニュアルが口酸っぱく警告しているとおり、ほとんどの場合はクラスを継承してメソッドをオーバーライドしていくほうが簡単かつ安全でしょう。

今回の拡張もLog.phpを継承したMY_Log.phpを作成することにします。

以下がクラスの全貌です。

MY_Log.php
class MY_Log extends CI_Log {

  private function _write_log($level, $msg)
  {
    $category = isset($this->_levels[$level]) ? '' : $level.'-';

    $filepath = $this->_log_path.'log-'.$category.date('Y-m-d').'.'.$this->_file_ext;
    $message = '';

    if ( ! file_exists($filepath))
    {
      $newfile = TRUE;
      // Only add protection to php files
      if ($this->_file_ext === 'php')
      {
        $message .= "<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>\n\n";
      }
    }

    if ( ! $fp = @fopen($filepath, 'ab'))
    {
      return FALSE;
    }

    flock($fp, LOCK_EX);

    // Instantiating DateTime with microseconds appended to initial date is needed for proper support of this format
    if (strpos($this->_date_fmt, 'u') !== FALSE)
    {
      $microtime_full = microtime(TRUE);
      $microtime_short = sprintf("%06d", ($microtime_full - floor($microtime_full)) * 1000000);
      $date = new DateTime(date('Y-m-d H:i:s.'.$microtime_short, $microtime_full));
      $date = $date->format($this->_date_fmt);
    }
    else
    {
      $date = date($this->_date_fmt);
    }

    $message .= $this->_format_line($level, $date, $msg);

    for ($written = 0, $length = self::strlen($message); $written < $length; $written += $result)
    {
      if (($result = fwrite($fp, self::substr($message, $written))) === FALSE)
      {
        break;
      }
    }

    flock($fp, LOCK_UN);
    fclose($fp);

    if (isset($newfile) && $newfile === TRUE)
    {
      chmod($filepath, $this->_file_permissions);
    }

    return is_int($result);
  }

  /**
   * Write Log File
   *
   * Generally this function will be called using the global log_message() function
   *
   * @param string  $level  The error level: 'error', 'debug' or 'info'
   * @param string  $msg    The error message
   * @return    bool
   */
  public function write_log($level, $msg)
  {
    if ($this->_enabled === FALSE)
    {
      return FALSE;
    }

    $level = strtoupper($level);

    if ( ! isset($this->_levels[$level]))
    {
      return $this->_write_log($level, $msg);
    }

    if (
      isset($this->_levels[$level])
      && (($this->_levels[$level] > $this->_threshold))
      && ! isset($this->_threshold_array[$this->_levels[$level]])
    )
    {
      return FALSE;
    }

    return $this->_write_log($level, $msg);
  }

}

このコードをapplication/core/MY_Log.phpの位置に配置すると拡張処理が動作します。

どんなものが出力されるのか

先述のように、

log_message('debug', 'デバックメッセージ');

と書いても拡張前と書き出されるログは変わりません。
第一引数が「error」「debug」「info」の場合は変わらず、設定ファイルに設定できるしきい値に応じてデフォルトのログファイルに出力されたりされなかったりします。

今回の拡張が役立つのは第一引数にそれら以外の文字列を設定した場合です。

log_message('custome', 'カスタムメッセージ');
log-custome-2018-10-05.php
<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>

DEBUG - 2018-10-05 17:36:15 --> カスタムメッセージ

上述のように第一引数をcustomeと設定すると、デフォルトのログファイル名中、log日付の間に第一引数と同じ文字列が挿入されたファイルが作成され、以後同じ第一引数が設定されたlog_message()関数はそのファイルへログを追記します。

こうすることでログの種類によってログファイルをカテゴリー分けできるのです。

Go-Noji
PHPとJavaScriptを扱う現代の呪術師
http://noji.wpblog.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away