{ 2011.12.8 }

CakePHPでのSQLのログ

    はてなブックマーク - CakePHPでのSQLのログ
    このエントリーをはてなブックマークに追加

    Fusicの中野です。

    表題のとおり、CakePHPのログに関する小ネタを紹介します。
    ちなみに、使っているCakePHPのバージョンは1.3です。(CakePHP2.xなんて知りません)

    CakePHPでConfigure::read(“debug”) > 1の場合は画面にSQLのログが表示されます。
    ですが、運用中ではPHPのエラー表示などがされないように、Configure::read(“debug”) == 0の状態ではないかと思います。
    そうなると、すこしだけSQLの確認をしたいときなどちょっと面倒ですよね。

    CakePHPはConfigure::read(“debug”) > 1の場合、SQLのログはDboSourceの_queriesLogというメンバの配列に格納されていて、どうやらその配列の中身を画面に出力しているようです。

    そこで、こいつの中身が取れれば解決できるので・・・

    $db =& ConnectionManager::getDataSource($Model->useDbConfig);
    $db->fullDebug = true; // ここがfalseだとログを保存しない。$db->fullDebug = Configure::read() > 1みたいになってます。
    $db->_queriesLogMax = 200; // SQLがこの件数こえると配列に保存しないよ的なもの。

    みたいなことをfindを実行する前に書いてあげれば、_queriesLogに登録されるようです。

    だけど、これだと少々めんどいのでBehaviorにまとめてみましょう。

     
    class QueryLogBehavior extends ModelBehavior {
      var $__settings = array();
      var $_queriesLogMax = 999;
     
      function setup( &$Model, $settings = array() ){
       $this->__settings[ $Model->alias ] = array();
     }
     
      function make_query_key( $Model, $query ){ return get_class( $Model ) . "__" .  md5( serialize( $query ) ); }
      function add_query( $key ){
        return "'" . $key . "' = '" . $key . "'";
      }
     
      function beforeFind( &$Model, $query ){
        if( array_key_exists( "log", $query ) and $query["log"] ){
          $db =& ConnectionManager::getDataSource($Model->useDbConfig);
          $db->fullDebug = true;
          $db->_queriesLogMax = $this->_queriesLogMax;
          $key = $this->make_query_key( $Model, $query ); // いらないかも。
          if( array_key_exists( "conditions", $query ) ){
            $query["conditions"][] = $this->add_query( $key );
          }
          else {
            $query["conditions"] = array( $this->add_query( $key ) ); 
          }
          $this->__settings[$Model->alias][] = array( $key, $query["log"] );
        }
        return $query;
      }
     
      function afterFind( &$Model, $results, $primary ){
        $db =& ConnectionManager::getDataSource($Model->useDbConfig);
        $db->fullDebug = Configure::read() > 1;
        $db->_queriesLogMax = 200;
     
        $hit_sql = null; $level = LOG_DEBUG;
        foreach( $this->__settings[$Model->alias] as $keypair ){
          list( $key, $level ) = $keypair;
          foreach( $db->_queriesLog as $index => $query_log ){
            if( preg_match( "/^(.*)" . $this->add_query( $key ) . "(.*)$/", $query_log["query"], $regexp )) {
              $hit_sql = $regexp[1] . "" . $regexp[2];
              break;
            }
          }
        }
        if( !is_null( $hit_sql ) ) $this->log( $hit_sql, $level );
        return true;
      }
    }

    なんかこんな風に適当にBehaviorを追加して

    $this->Hoge->find( "all", array( "contain" => array(), "conditions" => <なんかの条件>, "log" => LOG_INFO ) );

    みたいにしてあげたら、app/tmp/log/debug.logにSQLが記述されます。これで任意のfindの処理のSQLをログにだしたりできます。
    データベースの設定でSQLのログだしとけよとかいうツッコミはなしで。

    Comments are closed.