Преамбула

Сегодня я хотел включить логирование всех действий приложения в таблицу в БД. В документации к Yii нашел информацию по классу CDbLogRoute, который отвечает за это, у него есть такая фича, как автосоздание таблицы в том случае, если она не существует.

Часть I. Завязка

После настройки (все по документации) в protected/config/main.php при попытке обновить окно приложения вылетел Exception. Фреймворк ругался: «Не могу я создать, дескать, таблицу 1 (CREATE TABLE 1)»; и выдал много информации, по которой я нашел следующий код в framework/logging/CDbLogRoute.php.

  1.  /**
  2.   * Initializes the route.
  3.   * This method is invoked after the route is created by the route manager.
  4.   */
  5.  public function init()
  6.  {
  7.      parent::init();
  8.   
  9.      $db=$this->getDbConnection();
  10.      $db->setActive(true);
  11.   
  12.      $sql="SELECT * FROM {$this->logTableName} WHERE 0";
  13.      try
  14.      {
  15.          $db->createCommand($sql)->execute();
  16.      }
  17.      catch(Exception $e)
  18.      {
  19.          // The log table does not exist
  20.          if($this->autoCreateLogTable)
  21.              $this->createLogTable($db,$this->autoCreateLogTable);
  22.          else
  23.              throw new CException(Yii::t('yii','CDbLogRoute requires database table "{table}" to store log messages.',
  24.                  array('{table}'=>$this->logTableName)));
  25.      }
  26.  }

Сразу насторожила такая строка: $this->createLogTable($db,$this->autoCreateLogTable), т.к. чуть ниже можно увидеть определение функции createLogTable($db, $tableName), а $this->autoCreateLogTable никак не является $this->logTableName. Заменил одну переменную на другую и, вуаля, таблица создалась. Но это не конец...

Часть II. Страсти нарастали

Таблица попыталась создаться во второй раз и в третий, и все это время я получал Exception и трейс выполнения. Выяснилось, что запуском для автоматического создания таблицы является SQL-код "SELECT * FROM {$this->logTableName} WHERE 0". Тут стоит сказать, что такой код успешно будет выполнен в MySQL, но в PostgreSQL конструкция "WHERE 0" вызывает ошибку. Пришлось заменить это на код, который успешно выполнится и в PostgreSQL, и в MySQL: "SELECT * FROM {$this->logTableName} WHERE TRUE" (или можно вписать вместо TRUE - FALSE, это на вкус и цвет). Таблица создаваться автоматически перестала. Но и это ещё не конец!

Часть III. Заключительная

Появились ошибки от PostgreSQL, что, мол, VALUE не является INTEGER'ом и не хочу я INSERT'ить в таблицу логов.

Бросив очередной взгляд на трейс выполнения, я заметил, что ошибка возникает при вызове метода processLogs($logs) в самом низу CDbLogRoute.php. Внимательно посмотрев, что же и в какие поля хочет запихать наш фреймворк, я пришел к выводу, что стоит поменять местами элементы массива $log, которые присваются в запросе на вставку в таблицу.

Было:

  1.  foreach($logs as $log)
  2.  {
  3.      $command->bindValue(':level',$log[0]);
  4.      $command->bindValue(':category',$log[1]);
  5.      $command->bindValue(':logtime',(int)$log[2]);
  6.      $command->bindValue(':message',$log[3]);
  7.      $command->execute();
  8.  }

Стало:

  1.  foreach($logs as $log)
  2.  {
  3.      $command->bindValue(':level',$log[2]);
  4.      $command->bindValue(':category',$log[1]);
  5.      $command->bindValue(':logtime',(int)$log[3]);
  6.      $command->bindValue(':message',$log[0]);
  7.      $command->execute();
  8.  }

Часть IV. О забывчивости

После всех этих переписок у меня все заработало, логи и трейсы посыпались в таблицу. Настало счастье!.. На локальной машине... Я совсем забыл, что коммитнулся, и у меня автодеплойер развернул новый код (сработал по изменению версии репозитория) на тестировочном сервере. Код же самого фреймворка я в проект не включал. Не хорошо получилось с коммерческим директором, который только-только залез посмотреть разработку и увидел Exception'ы и трейсы. Пробежка по клавиатуре с запуском консоли и ssh'ем на сервер, быстрым открытием нужного файла, заменой старого кода на новый, решила и эту проблему.

Эпилог. Фуххх!..

Через пару часов (как появилось свободное время), я отписал в Bugtracker эту проблему и ее решение, а всего лишь через 6 часов после этого, автор Yii - Qiang ее уже пофиксил, 1 апреля будет релиз с исправлением этой ошибки.

Так приятно помогать людям и участвовать в общем деле, особенно когда тебе говорят за это Thanks!