17Ошибки и логирование
Обработчик ошибок и своя страница ошибки, HTTP-исключения, формат ошибок для API; уровни и категории логов, цели (файл, БД, email), фильтрация и профилирование.
Yii превращает все PHP-ошибки в исключения, показывает их с исходным кодом в режиме отладки и красивой страницей в проде. Логи пишутся через Yii::error()/warning()/info()/debug() и разводятся целями по файлам, базе, почте.
Обработка ошибок#
Компонент errorHandler включён по умолчанию (отключается константой YII_ENABLE_ERROR_HANDLER = false).
- Не фатальные ошибки (warning, notice) становятся
yii\base\ErrorException— их можно ловить. - При
YII_DEBUG = trueпоказывается стек вызовов и код; приfalse— только сообщение. - Исключения-наследники
yii\base\UserExceptionпоказываются без стека всегда: это «ошибки пользователя».
try {
10 / 0;
} catch (\yii\base\ErrorException $e) {
Yii::warning('Деление на ноль');
}
throw new \yii\web\NotFoundHttpException('Такой страницы нет'); // → 404 с правильным статусомСвоя страница ошибки#
Лучший способ — действие контроллера:
'components' => [
'errorHandler' => [
'errorAction' => 'site/error',
// 'maxSourceLines' => 20, 'errorView', 'exceptionView' — свои шаблоны
],
],public function actions()
{
return ['error' => ['class' => 'yii\web\ErrorAction']]; // рендерит views/site/error.php
}В представлении доступны $name, $message, $exception (с statusCode). Шаблоны basic и advanced уже содержат это действие.
Ошибки в формате API#
Если response->format не HTML, обработчик кладёт в response->data массив с полями name, message, code, status — он уходит как JSON/XML. Формат можно менять на событии beforeSend:
'response' => [
'on beforeSend' => function ($event) {
$response = $event->sender;
if ($response->data !== null) {
$response->data = ['success' => $response->isSuccessful, 'data' => $response->data];
$response->statusCode = 200;
}
},
],Логирование#
Запись#
Yii::debug('начало расчёта', __METHOD__); // уровень trace — только при разработке
Yii::info('пользователь вошёл', 'app\auth');
Yii::warning('неожиданное состояние');
Yii::error('не удалось отправить письмо', __METHOD__);Второй аргумент — категория. __METHOD__ даёт app\controllers\SiteController::actionLogin — так категории образуют иерархию, по которой удобно фильтровать (yii\db\*). Сообщение может быть строкой, массивом или объектом (будет экспортирован VarDumper).
Цели#
Компонент log должен быть в bootstrap, чтобы ловить сообщения с самого начала запроса:
return [
'bootstrap' => ['log'],
'timeZone' => 'Europe/Moscow',
'components' => [
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0, // сколько строк стека добавлять к сообщению
'flushInterval' => 1000, // передавать целям каждые N сообщений (и в конце запроса)
'targets' => [
'file' => [
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
'categories' => ['yii\db\*', 'yii\web\HttpException:*'],
'except' => ['yii\web\HttpException:404'],
'logVars' => ['_SERVER'], // какие глобальные массивы прикладывать; [] — никакие
'maskVars' => ['_SERVER.HTTP_X_PASSWORD', '_SERVER.*_SECRET'],
'exportInterval' => 1000, // писать в хранилище каждые N отфильтрованных сообщений
'prefix' => function ($message) {
return '[' . (Yii::$app->user->id ?? '-') . ']';
},
],
'email' => [
'class' => 'yii\log\EmailTarget',
'levels' => ['error'],
'categories' => ['yii\db\*'],
'message' => [
'from' => ['log@example.com'], 'to' => ['admin@example.com'], 'subject' => 'Ошибки БД',
],
],
],
],
],
];| Цель | Куда |
|---|---|
FileTarget | runtime/log/app.log (ротация по размеру) |
DbTarget | таблица БД (yii migrate --migrationPath=@yii/log/migrations) |
EmailTarget | письмо через mailer |
SyslogTarget | системный syslog() |
Уровни: error, warning, info, trace (это Yii::debug()), profile. Без levels цель берёт всё. Формат строки: время [IP][ID пользователя][ID сессии][уровень][категория] текст.
Отключить цель на лету: Yii::$app->log->targets['file']->enabled = false. Своя цель — наследник yii\log\Target с методом export().
Профилирование#
Yii::beginProfile('import');
// код
Yii::beginProfile('parse'); // вложенные пары должны быть сбалансированы
Yii::endProfile('parse');
Yii::endProfile('import');Результаты — сообщения уровня profile; их показывает панель отладчика. Так, например, yii\db\Command замеряет каждый SQL-запрос.
Указать errorAction => 'site/error' у errorHandler и объявить действие error через yii\web\ErrorAction с представлением views/site/error.php.
Компоненты создаются лениво; без bootstrap сообщения, записанные до первого обращения к log, могли бы потеряться.
Цель с levels => ['error'], categories => ['yii\db\*']; для 404 используют except => ['yii\web\HttpException:404'].
Уровнем: debug пишет trace-сообщения для разработки, info — информационные, которые уместны и в проде.
Сколько уровней стека вызовов прикладывать к каждому сообщению; дорого, поэтому включают только при YII_DEBUG.