Журналювання ============ Yii надає гнучкий та розширюваний функціонал протоколювання. Повідомлення можна класифікувати відповідно до рівня протоколювання і типом повідомлень. Використовуючи фільтри за рівнем та категорією, можна направити потік повідомлень у файли, електронну пошту, вікно браузера і т.д. Протоколювання повідомлень -------------------------- Повідомлення може бути запротокольовано шляхом виклику [Yii::log] або [Yii::trace]. Різниця між ними полягає у тому, що останній пише в лог тільки тоді, коли додаток працює у [режимі відладки](/doc/guide/basics.entry#debug-mode). ~~~ [php] Yii::log($message, $level, $category); Yii::trace($message, $category); ~~~ Для внесення повідомлення у лог, необхідно вказати категорію і рівень повідомлення. Категорія представляє собою рядок формату `xxx.yyy.zzz`, що дуже схоже з форматом представлення [псевдоніма шляху](/doc/guide/basics.namespace). Наприклад, якщо повідомлення додається у лог в [CController], ми можемо використовувати категорію `system.web.CController`. Рівень повідомлення може мати одне із наступних значень: - `trace`: цей рівень використовується методом [Yii::trace]. Він призначений для відстеження процесу виконання додатка у ході розробки; - `info`: цей рівень призначений для протоколювання інформації загального характеру; - `profile`: даний рівень використовується для профілювання (вимірювання) продуктивності; - `warning`: цей рівень призначений для повідомлень-попереджень; - `error`: цей рівень використовується для повідомлень про критичні помилки. Маршрутизація повідомлень ------------------------- Повідомлення, що протоколюються із використанням [Yii::log] або [Yii::trace], зберігаються у памʼяті. Як правило, нам потрібно або відобразити їх у вікні браузера, або зберегти у файлі, відправити електронним листом та ін. Напрямок повідомлень у різні місця призначення називається *маршрутизацією повідомлень*. В Yii за маршрутизацію повідомлень відповідає компонент додатка [CLogRouter]. Цей компонент керує безліччю так званих *маршрутів повідомлень*. Кожен маршрут представляє одне місце призначення потоку повідомлень. Повідомлення, що направляються на той чи інший маршрут, можна відфільтрувати у залежності від їх рівня і типу. Для того, щоб скористатися маршрутизацією повідомлень, нам необхідно встановити і довантажити заздалегідь компонент додатка [CLogRouter]. Крім того, необхідно налаштувати властивість [routes|CLogRouter::routes] цього компонента, вказавши маршрути повідомлень, які передбачається використовувати. Нижче наведено приклад необхідної [конфігурації додатка](/doc/guide/basics.application#application-configuration): ~~~ [php] 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 можна виключати певні категорії: ~~~ [php] '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]: відображає повідомлення про продуктивність у кінці поточної сторінки. ~~~ [php] array( ...... 'preload'=>array('log'), 'components'=>array( ...... 'log'=>array( 'class'=>'CLogRouter', 'routes'=>array( array( 'class'=>'CProfileLogRoute', 'report'=>'summary', // Відображає час виконання кожного відміченого блоку кода. // Значення "report" також можна вказати як "callstack". ), ...інші маршрути... ), ), ), ) ~~~ > Info|Інформація: Маршрутизація повідомлення відбувається у кінці кожного поточного циклу обробки запиту, у момент, коли викликається подія [onEndRequest|CApplication::onEndRequest]. Для переривання процесу обробки поточного запиту, використовуйте метод [CApplication::end()] замість `die()` або `exit()`. [CApplication::end()] викликає подію [onEndRequest|CApplication::onEndRequest], що дозволяє коректно запротоколювати повідомлення. Фільтрація повідомлень ---------------------- Як вже згадувалося вище, повідомлення можна відфільтрувати по їх рівню і типу до того, як вони будуть направлені тим чи іншим маршрутом. Це здійснюється шляхом налаштування властивостей [levels|CLogRoute::levels] та [categories|CLogRoute::categories] відповідного маршруту. Якщо необхідно вказати кілька рівнів або типів, значення повинні бути розділені комами. Оскільки типи повідомлень вказуються у форматі `xxx.yyy.zzz`, ми можемо сприймати їх як ієрархію типів. Зокрема, ми говоримо, що `xxx` є батьком `xxx.yyy`, а останній у свою чергу є батьком для `xxx.yyy.zzz`. Тому для вказівки типу `xxx`, а також всіх його типів-нащадків можна використовувати вираз `xxx.*`. Збереження контексту повідомлень -------------------------------- Ми можемо зберігати додаткову інформацію, таку як визначені змінні PHP (`$_GET`, `$_SERVER`), ID сесії, імʼя користувача і т.д. Для цього необхідно задати необхідний фільтр у властивості [CLogRoute::filter]. До складу фреймворку входить зручний клас [CLogFilter], який може бути використаний у якості фільтра у більшості випадків. За замовчуванням, [CLogFilter] буде записувати повідомлення разом з такими змінними, як `$_GET` и `$_SERVER`, які зазвичай містять цінну системну інформацію. можна налаштувати [CLogFilter] таким чином, щоб перед кожним повідомленням записувати ID сесії, імʼя користувача та інші дані, які можуть полегшити пошук по великій кількості повідомлень. Наступні налаштування включають запис контексту повідомлень. У кожного журнального маршруту може бути заданий свій фільтр. За замовчуванням ніякого фільтра не задано. ~~~ [php] 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` визначає кількість шарів кожного стека виклику, яке повинно бути записано. Ця інформація особливо корисна на стадії розробки, тому що може допомогти нам визначити місця, у яких викликаються трасуючі повідомлення. Профілювання продуктивності --------------------------- Для цілей вимірювання продуктивності використовується спеціальний тип повідомлень. Його можна використовувати для вимірювання часу виконання деякого блоку коду та визначення вузьких місць у продуктивності. Для того, щоб виміряти продуктивність, необхідно вказати ту частину коду, виконання якої буде відслідковуватися. Використовуючи такі методи, ми відзначаємо початок і кінець кожного вимірюваного блоку коду: ~~~ [php] Yii::beginProfile('blockID'); …блок профільованого коду… Yii::endProfile('blockID'); ~~~ де `blockID` — це унікальний ідентифікатор блоку коду. Зверніть увагу, що блоки коду повинні мати коректну вкладеність, тобто вони не можуть перетинатися один з одним. Вони або йдуть паралельно, або один блок повністю включає інший. Для того, щоб побачити результат профілювання, нам буде потрібно встановити компонент додатка [CProfileLogRoute], відповідальний за відповідний маршрут протоколювання. Тут все аналогічно роботі із простими маршрутами повідомлень. Маршрут [CProfileLogRoute] відобразить результати вимірювання продуктивності внизу поточної сторінки. Профілювання SQL-запитів ------------------------ Профілювання особливо корисне при роботі із базою даних, так як SQL-запити часто є найвужчим місцем продуктивності додатка. Незважаючи на те, що ми можемо вкласти у потрібні місця `beginProfile` та `endProfile` для того, щоб заміряти час, витрачений на кожен SQL-запит, Yii надає більш зручне рішення даної проблеми. Встановивши у налаштуваннях додатка [CDbConnection::enableProfiling] у `true`, ми отримаємо профілювання всіх виконуваних SQL-запитів. Отримані результати можна вивести за допомогою вищезгаданого [CProfileLogRoute], що показує скільки часу зайняв той чи інший SQL-запит . Для виведення загальної кількості запитів і загального часу виконання можна використовувати [CDbConnection::getStats()].