Преамбула
Сегодня я хотел включить логирование всех действий приложения в таблицу в БД. В документации к Yii нашел информацию по классу CDbLogRoute, который отвечает за это, у него есть такая фича, как автосоздание таблицы в том случае, если она не существует.
Часть I. Завязка
После настройки (все по документации) в protected/config/main.php при попытке обновить окно приложения вылетел Exception. Фреймворк ругался: «Не могу я создать, дескать, таблицу 1 (CREATE TABLE 1)»; и выдал много информации, по которой я нашел следующий код в framework/logging/CDbLogRoute.php.
/**
* Initializes the route.
* This method is invoked after the route is created by the route manager.
*/public function init()
{parent::init();
$db=$this->getDbConnection();
$db->setActive(true);
$sql="SELECT * FROM {$this->logTableName} WHERE 0";
try{$db->createCommand($sql)->execute();
}catch(Exception $e)
{// The log table does not exist
if($this->autoCreateLogTable)
$this->createLogTable($db,$this->autoCreateLogTable);
elsethrow new CException(Yii::t('yii','CDbLogRoute requires database table "{table}" to store log messages.',
array('{table}'=>$this->logTableName)));
}}
Сразу насторожила такая строка: $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, которые присваются в запросе на вставку в таблицу.
Было:
foreach($logs as $log)
{$command->bindValue(':level',$log[0]);
$command->bindValue(':category',$log[1]);
$command->bindValue(':logtime',(int)$log[2]);
$command->bindValue(':message',$log[3]);
$command->execute();
}
Стало:
foreach($logs as $log)
{$command->bindValue(':level',$log[2]);
$command->bindValue(':category',$log[1]);
$command->bindValue(':logtime',(int)$log[3]);
$command->bindValue(':message',$log[0]);
$command->execute();
}
Часть IV. О забывчивости
После всех этих переписок у меня все заработало, логи и трейсы посыпались в таблицу. Настало счастье!.. На локальной машине... Я совсем забыл, что коммитнулся, и у меня автодеплойер развернул новый код (сработал по изменению версии репозитория) на тестировочном сервере. Код же самого фреймворка я в проект не включал. Не хорошо получилось с коммерческим директором, который только-только залез посмотреть разработку и увидел Exception'ы и трейсы. Пробежка по клавиатуре с запуском консоли и ssh'ем на сервер, быстрым открытием нужного файла, заменой старого кода на новый, решила и эту проблему.
Эпилог. Фуххх!..
Через пару часов (как появилось свободное время), я отписал в Bugtracker эту проблему и ее решение, а всего лишь через 6 часов после этого, автор Yii - Qiang ее уже пофиксил, 1 апреля будет релиз с исправлением этой ошибки.
Так приятно помогать людям и участвовать в общем деле, особенно когда тебе говорят за это Thanks!

