/** * Перехватчик исключений. * * Ловит исключения, которые не были пойманы ранее. Последний шанс обработать ошибку. Например, записать в лог или * намылить админу. Можно так же вежливо откланяться юзеру. * * После выполнения этого обработчика программа остановится, обеспечено PHP. * * Если указано предыдущее исключение, отсюда не пишем в лог. Сей факт указывает на то, что реальное исключение * уже было поймано и обработано. Считаем, что необходимость логирования была решена в предыдущих обработчиках. * * Прим: для поддержки PHP 7.0 тип ожидаемого параметра расширен, * см. {@see http://php.net/manual/ru/function.set-exception-handler.php PHP::set_exception_handler()} * * @param \Throwable $ex */ public static function exceptionHandler($ex) { $class = get_class($ex); $message = nl2br($ex->getMessage()); $file = str_replace(ROOT_PATH, '/', $ex->getFile()); $line = $ex->getLine(); $trace = $ex->getTraceAsString(); if (isConsoleInterface()) { echo 'Исключение: ' . $class . PHP_EOL . PHP_EOL . $message . PHP_EOL . PHP_EOL . 'Стек вызовов:' . PHP_EOL . $trace . PHP_EOL; return; } if (!headers_sent()) { header('500 Internal Server Error'); header('Content-Type: text/html; charset=UTF-8'); } if (DEBUG) { echo Render::fetch('exception.htm', compact('class', 'message', 'file', 'line', 'trace')); } else { echo Render::fetch('exception_prod.htm', ['domain' => Env::domainName()]); if ($ex->getPrevious() === null) { $logger = App::logger(); $logger->addTyped("Class: {$class}" . PHP_EOL . "Message: {$message}" . PHP_EOL . "Source: {$file}:{$line}" . PHP_EOL . PHP_EOL . "Trace: {$trace}", $logger::EXCEPTION); } } }
/** * Письмо админу с текущим сообщение лога. * * @return void */ private function mailToAdmin() { $logIt = $this->logIt; if (!($mailTo = $this->conf['_mail'])) { $this->addTyped('Не задан email админа, не могу отправить сообщение от логера.', ILogger::ENGINE); return; } $domain = Env::domainName(); $date = $logIt['ts']->format('Y/m/d H:i:s P'); $rn = PHP_EOL; $letters['text'] = 'Сообщение от логера' . $rn . $rn . $logIt['message'] . $rn . $rn . "Тип: {$logIt['type']}{$rn}" . "Источник: {$logIt['source']}" . $rn . $rn . "URL запроса:{$logIt['request']}" . $rn . "IP юзера: {$logIt['userIP']}" . $rn . $rn . "{$date} (c) {$domain}"; $vars = ['message' => nl2br($logIt['message']), 'type' => $logIt['type'], 'source' => $logIt['source'], 'request' => $logIt['request'], 'userIP' => $logIt['userIP'], 'date' => $date, 'homeURL' => Env::indexPage(), 'domain' => $domain]; $letters['html'] = Render::fetch('log_letter.htm', $vars); $from = App::conf('noreply_mail') ?: "noreply@{$domain}"; if (!Mailer::complex($from, $mailTo, "Сообщение от логера сайта {$domain}", $letters)) { $this->addTyped('Не удалось отправить сообщение от логера.', ILogger::ENGINE); } }