Журналирование

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

1. Протоколирование сообщений

Сообщение может быть запротоколировано путем вызова Yii::log или Yii::trace. Разница между ними заключается в том, что последний пишет в лог только тогда, когда приложение работает в режиме отладки.

Yii::log($message, $level, $category);
Yii::trace($message, $category);

Для внесения сообщения в лог, необходимо указать категорию и уровень сообщения. Категория представляет собой строку формата xxx.yyy.zzz, что очень схоже с форматом представления псевдонима пути. Например, если сообщение добавляется в лог в CController, мы можем использовать категорию system.web.CController. Уровень сообщения может иметь одно из следующих значений:

  • trace: этот уровень используется методом Yii::trace. Он предназначен для отслеживания процесса выполнения приложения в ходе разработки;

  • info: этот уровень предназначен для протоколирования информации общего характера;

  • profile: данный уровень используется для профилирования (измерения) производительности;

  • warning: этот уровень предназначен для сообщений-предупреждений;

  • error: этот уровень используется для сообщений о критических ошибках.

2. Маршрутизация сообщений

Сообщения, протоколируемые с использованием Yii::log или Yii::trace, хранятся в памяти. Как правило, нам требуется либо отобразить их в окне браузера, либо сохранить в файле, отправить электронным письмом и пр. Направление сообщений в различные места назначения называется маршрутизацией сообщений.

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

Для того, чтобы воспользоваться маршрутизацией сообщений, нам необходимо установить и подгрузить заранее компонент приложения CLogRouter. Кроме того, необходимо настроить свойство routes этого компонента, указав маршруты сообщений, которые предполагается использовать. Ниже приведен пример необходимой конфигурации приложения:

array('preload'=>array('log'),
    'components'=>array('log'=>array(
            'class'=>'CLogRouter',
            'routes'=>array(
                array(
                    'class'=>'CFileLogRoute',
                    'levels'=>'trace, info',
                    'categories'=>'system.*',
                ),
                array(
                    'class'=>'CEmailLogRoute',
                    'levels'=>'error, warning',
                    'emails'=>'admin@example.com',
                ),
            ),
        ),
    ),
)

В примере выше, у нас есть два маршрута сообщений. Первый - CFileLogRoute - сохраняет сообщения в папке приложения для временных файлов runtime. Сохраняются только сообщения с уровнем trace или info и чья категория начинается с system.. Второй маршрут - CEmailLogRoute - отправляет сообщения на указанный электронный адрес. Отправляются только сообщения уровня error или warning.

Начиная с Yii версии 1.1.13 можно исключать определённые категории:

'routes'=>array(
        array(
            'class'=>'CEmailLogRoute',
            'levels'=>'error, warning',
            'except'=>'system.CModule.*' // отсылаем почтой всё кроме сообщений от CModule
            'emails'=>'admin@example.com',
        ),
        array(
            'class'=>'CWebLogRoute',
            'categories'=>'system.db.*',
            'except'=>'system.db.ar.*', // показываем всё, что касается базы данных, но не касается AR
        ),

В Yii доступны для использования следующие маршруты сообщений:

  • CDbLogRoute: сохраняет сообщения в таблицу базы данных;
  • CEmailLogRoute: отправляет сообщения на указанный адрес электронной почты;
  • CFileLogRoute: сохраняет сообщения во временной папке приложения;
  • CWebLogRoute: отображает сообщения в конце текущей страницы;
  • CProfileLogRoute: отображает сообщения о производительности в конце текущей страницы.
array(
    ......
    'preload'=>array('log'),
    'components'=>array(
        ......
        'log'=>array(
            'class'=>'CLogRouter',
            'routes'=>array(
                array(
                    'class'=>'CProfileLogRoute',
                    'report'=>'summary',
                    // Показывает время выполнения каждого отмеченного блока кода.
                    // Значение "report" также можно указать как "callstack".
                ),
                ...остальные маршруты...
            ),
        ),
    ),
)

Информация: Маршрутизация сообщения происходит в конце каждого текущего цикла обработки запроса, в момент, когда вызывается событие onEndRequest. Для прерывания процесса обработки текущего запроса, используйте метод CApplication::end() вместо die() или exit(). CApplication::end() вызывает событие onEndRequest, что позволяет корректно запротоколировать сообщения.

3. Фильтрация сообщений

Как уже упоминалось выше, сообщения можно отфильтровать по их уровню и типу до того, как они будут направлены тем или иным маршрутом. Это осуществляется путем настройки свойств levels и categories соответствующего маршрута. Если необходимо указать несколько уровней или типов, значения должны быть разделены запятыми.

Поскольку типы сообщений указываются в формате xxx.yyy.zzz, мы можем воспринимать их как иерархию типов. В частности, мы говорим, что xxx является родителем xxx.yyy, а последний в свою очередь является родителем для xxx.yyy.zzz. Поэтому для указания типа xxx, а также всех его типов-потомков можно использовать выражение xxx.*.

4. Сохранение контекста сообщений

Мы можем сохранять дополнительную информацию, такую как предопределённые переменные PHP ($_GET, $_SERVER), ID сессии, имя пользователя и т.д. Для этого необходимо задать необходимый фильтр в свойстве CLogRoute::filter.

В состав фреймворка входит удобный класс CLogFilter, который может быть использован в качестве фильтра в большинстве случаев. По умолчанию, CLogFilter будет записывать сообщение вместе с такими переменными, как $_GET и $_SERVER, которые обычно содержат ценную системную информацию. Можно настроить CLogFilter таким образом, чтобы перед каждым сообщением записывать ID сессии, имя пользователя и другие данные, которые могут облегчить поиск по большому количеству сообщений.

Следующие настройки включают запись контекста сообщений. У каждого журнального маршрута может быть задан свой фильтр. По умолчанию никакого фильтра не задано.

array('preload'=>array('log'),
    'components'=>array('log'=>array(
            'class'=>'CLogRouter',
            'routes'=>array(
                array(
                    'class'=>'CFileLogRoute',
                    'levels'=>'error',
                    'filter'=>'CLogFilter',
                ),
                …other log routes),
        ),
    ),
)

Yii поддерживает журналирование информации стека вызова в сообщениях, протоколируемых путем вызова Yii::trace. По умолчанию, данная особенность отключена, т.к. снижает производительность. Для ее использования, необходимо просто определить константу YII_TRACE_LEVEL в начале входного скрипта (до включения файла yii.php) целым числом большим нуля. Тогда Yii будет добавлять в каждое трассирующее сообщение имя файла и номер строки стека вызова, в которых был сделан вызов кода. Число YII_TRACE_LEVEL определяет количество слоев каждого стека вызова, которое должно быть записано. Эта информация особенно полезна на стадии разработки, так как может помочь нам определить места, в которых вызываются трассирующие сообщения.

5. Профилирование производительности

Для целей измерения производительности используется специальный тип сообщений. Его можно использовать для измерения времени исполнения некоторого блока кода и определения узких мест в производительности.

Для того, чтобы измерить производительность, необходимо указать ту часть кода, выполнение которой будет отслеживаться. Используя следующие методы, мы отмечаем начало и конец каждого измеряемого блока кода:

Yii::beginProfile('blockID');
…блок профилируемого кода…
Yii::endProfile('blockID');

где blockID — это уникальный идентификатор блока кода.

Обратите внимание, что блоки кода должны иметь корректную вложенность, т.е. они не могут пересекаться друг с другом. Они либо идут параллельно, либо один блок полностью включает другой.

Для того, чтобы увидеть результат профилирования, нам потребуется установить компонент приложения CProfileLogRoute, отвечающий за соответствующий маршрут протоколирования. Здесь все аналогично работе с простыми маршрутами сообщений. Маршрут CProfileLogRoute отобразит результаты измерения производительности внизу текущей страницы.

6. Профилирование SQL-запросов

Профилирование особенно полезно при работе с базой данных, так как SQL-запросы часто являются самым узким местом производительности приложения. Несмотря на то, что мы можем вставить в нужные места beginProfile и endProfile для того, чтобы замерить время, затраченное на каждый SQL-запрос, Yii предоставляет более удобное решение данной проблемы.

Выставив в настройках приложения CDbConnection::enableProfiling в true, мы получим профилирование всех выполняемых SQL-запросов. Полученные результаты можно вывести при помощи вышеупомянутого CProfileLogRoute, показывающего, какой SQL-запрос сколько времени занял. Для вывода общего количества запросов и общего времени выполнения можно использовать CDbConnection::getStats().

Be the first person to leave a comment

Please to leave your comment.