Локализация ошибок - energy-coresky/air GitHub Wiki

Генерация ошибок

В SKY-приложениях, досрочное прекращение работы скриптов, может быть вызвано шестью способами:

  1. throw new Error(desc) - исключительные ситуации, ошибки, вызванные кодом программиста или ядром PHP. Такие исключительные ситуации всегда регистрируются в CRASH логе. Их быть не должно и если они возникли, код скрипта должен быть исправлен. Код ответа HTTP, для не консольных скриптов и для $sky->fly != HEAVEN::J_ACT, если явно не переопределен, равен 404. Начиная с PHP версии 7, класс Error является базовым для всех ошибок - исключений.

  2. фатальные ошибки PHP (до PHP 7) - тоже самое как для пункта 1, но только описание исключительных ситуаций всегда обеспечивается ядром PHP.

  3. throw new Stop(desc) - исключительные ситуации никогда не регистрируются в CRASH логе. Если явно не переопределено, HTTP ответ сервера равен 200. Специальный случай: throw new Stop без параметров: скрипт останавливает своё выполнение, а в STDOUT ничего не дописывается.

  4. throw new Hacker(desc) - исключительная ситуация, вызванная внешними по отношению к скрипту событиями. Такие ситуации могут возникать, например, при попытках взлома кода приложения. Код ответа HTTP, если явно не переопределен, равен 404. Для лога ошибок, throw new Hacker(..) никогда не считается ошибкой. При детектировании попыток взлома кода приложения, имеет смысл прекратить выполнение скрипта, и не считать это ошибкой программиста.

  5. инструкция PHP exit (или синоним die) - специальная исключительная ситуация, логически равноправна throw new Hacker. К сожалению, в стеке вызовов PHP, выполнение exit отсутствует и невозможно детектировать, в каком месте кода была применена инструкция. В коде CORESKY выполнение exit, детектируется на основании содержимого переменной $sky->tailed. Код ответа HTTP может быть 404 или 403 в зависимости от $sky->s_error_403.

  6. Все остальные исключительные ситуации, вызванные использованием других классов-потомков интерфейса Throwable. Логически - то-же самое что и для пункта 1. В SKY-приложениях не рекомендуется создавать такие новые классы, но описывать ошибки в desc в одном из вышеуказанных классов. Это не касается случаев, когда необходимо перехватить определенный тип исключений с помощью блоков try-catch.

Для $sky->fly == HEAVEN::J_ACT (читайте ниже), HTTP ответ от backend, всегда равен 200, несмотря на то, что любыми способами, могла предприниматься попытка установить другой код ответа. Установка кода ответа, которая описывается здесь, касается протекания скриптов с другим $sky->fly.

Под desc подразумевается текстовое описание ошибки. Может начинаться с HTTP кода ошибки от 100 и до 599. Если код указан, он будет использован в ответе. В throw new Error(desc), текстовое описание может отсутствовать, но содержаться только номер ошибки от 1 до 99. Такие номера ошибок не переопределят код HTTP ответа, который останется равен 404.

Также, ядро PHP может генерировать несколько типов не фатальных ошибок. В коде SKY-приложений, для генерации таких ошибок, необходимо использовать функцию trace(..), где второй параметр true.

В классе SKY, имеется метод SKY::check_other(..), который может запускаться по некоторому алгоритму и делать дополнительные LINT-проверки выявляя ошибки. Например, только в режиме DEV, когда произошла ошибка PHP.

Также, могут существовать специальные утилиты для поиска ошибок, например "Отчет глобальных определений".

Трассировка выполнения скриптов

В SKY-приложениях, для отладки скриптов и локализации ошибок, используется трассировка. В трассировку автоматически вносятся базовые точки выполнения скриптов, все SQL запросы (за исключением запросов, которые были вызваны с флагом SQL::NO_TRACE) и все ошибки. Чтобы добавить в трассировку ошибку, сообщение или содержимое некоторой переменной, используется функция trace(..):

void trace($var, $is_error = false, $line = 0, $file = '', $context = null)

$var - переменная любого типа или сообщение

$is_error - если true - ошибка, будет выделена красным фоном иначе сообщение

$line, $file, $context - остальные три параметра: если известно место возникновения ошибки, - должны передаваться в функцию trace. Если не известно - остаются параметры по умолчанию. В этом случае, место вызова функции trace, будет вычислено автоматически с помощью функции PHP debug_backtrace(). Также, можно передать число 1,2..N в параметре $line (когда $file равно пустой строке) - коррекцию глубины в стеке вызовов.

Программисту трассировка может передаваться двумя способами: обычная - в конце ответа HTML или X-трассировка - записывается в БД, см memory.1, memory.2, memory.3. Имеется специальный метод MVC::pdaxt(..) для отображения ссылок показа трассировок. X-трассировка работает в случае ajax, перед редиректом в скриптах или т.п.

Логи ошибок

Код Coresky построен так, что системный лог ошибок PHP, можно отключить. Кроме того, что в режиме DEBUG, собирается трассировка, ошибки могут также записываться в два лога в базе данных, таблице memory. Ошибки записываются в них по принципу FILO, логи имеют ограниченный размер - около 10 Кbytes, а запись в них не зависит от режимов DEV или DEBUG.

В логе ошибок (см. memory.4) регистрируются все ошибки, кроме exit, die, throw new Hacker. Лог активен при $sky->s_log_error == 1.

В crash логе (см. memory.5) регистрируются все фатальные завершения веб скриптов. Выполнение exit или die также, обычно считается фатальным завершением скрипта и связано со значением в $sky->tailed. Лог активен при $sky->s_log_crash == 1. При работе консольных скриптов, в этот лог никогда, ничего не пишется.

Подразумевается, что в хорошо отлаженном приложении, лог ошибок должен быть пуст. А в crash логе, можно наблюдать попытки взлома приложения на продакшн.

Для отладки приложений и поиска ошибок, имеется также Sky Log (см. memory.7), который возможно активировать и на DEV и на продакшн. Системный метод Rare::mail(..) использует запись подготовленных сообщений в этот лог в режиме DEV, а на продакшн, пытается реально отправить сообщение адресату:

# . . .
DEV ? SKY::log('mail', html($data)) : mail(..);

В первом параметре метода SKY::log(..), указывается цель, а во втором, - строка для записи в лог. В инструменте разработчиков, на вкладке Sky Log, можно просмотреть лог и установить цель. Если установлена цель off, - все попытки записать в этот лог будут проигнорированы, если цель all - наоборот, обработаны. Возможно, также добавлять, удалять и устанавливать конкретную цель. При использовании метода SKY::log(..) в коде приложений, в первом параметре, не следует указывать цели 'off' или 'all'.

Активная цель сохраняется в системном ghost: $sky->s_log_a, а массив custom-целей в $sky->s_log_y. Цели off и all из массива удалить нельзя. На продакшн, этот лог, всегда можно выключить из консоли:

$ sky eval "$sky->s_log_a = 'off'"

Если вызвать этот метод с одним параметром, логирование будет произведено в Cron Log (см. memory.6). Консольные скрипты (и не только), могут отмечать важные события в этом логе: SKY::log('money sent')

Классификация ошибок по типу обработки

  1. Не фатальные ошибки PHP, Coresky и приложений - можно отнести к одному классу. Эти ошибки вызывают popup с инструментами разработчика на DEV, а на PROD не видимы с точки зрения посетителя сайта.

  2. Фатальные до PHP 7 - скрипт прерывает выполнение в месте где возникла ошибка и продолжает в shutdown функции.

  3. Инструкция "exit или die" - скрипт прерывает выполнение в месте с ошибкой и продолжает в shutdown функции. Обработка подобна классу Hacker, а генерация этих ошибок используется при детектировании попыток взлома приложения.

  4. Вызванные потомками интерфейса Throwable - скрипт прерывает выполнение в месте с ошибкой и продолжает в "exception handler" и затем в shutdown функции. Обработка классов Stop, Hacker, Error и подобных отличается:

4.1. Stop - не является ошибкой.

4.2. Hacker - при детектировании попыток взлома

4.3. Error (и другие) - реальные фатальные ошибки

  1. Специальные ошибки Coresky - каждая ошибка по разному обрабатывается:

5.1. Gate error - на DEV вызывает popup с инструментами разработчика, а на PROD используется "die" для прерывания работы скрипта

5.2. Мягкие ошибки приложений - на DEV не вызывают dev-tools-popup

Обработка вышеприведенных типов ошибок, также отличается в зависимости от типа протекания скрипта в $sky->fly, как и в консольных скриптах.

Номер ошибки Описание значения $sky->error_no
0 Все идет без ньюансов. Нет ошибок
1 throw new Stop(..) - не ошибка, но прерывание работы скрипта. Переход в exception и затем в shutdown хэндлер.
2 "Мягкие" ошибки приложения. Например оповещение "страница не найдена", внутри layout приложения.
11 throw new Hacker(..) - попытка взлома заблокирована. Исключительная ситуация, но не ошибка программиста.
12 die(..) function - попытка взлома заблокирована. То-же самое.
21 Не фатальные ошибки PHP
22 Не фатальные ошибки Coresky. Генерируются с помощью функции trace(..), где второй параметр - true.
23 Не фатальные ошибки SQL запросов. Также, используется trace(..)
51 throw new Error(..) и подобные классы. Фатальные ошибки.
52 Фатальные ошибки до PHP 7
53 Фатальные ошибки SQL запросов
71 Gate Error для DEV. На продакшн, срабатывание Gate, выполняет PHP инструкцию die, а на DEV инициирует popup с инструментами разработчика, для настраивания врат.
72 На DEV указывает на необходимость показа инструментов разработчика для нотификации о Z-error. Т.е. ошибки, о которой невозможно было вовремя оповестить в силу специфики протекания скрипта, когда она была сгенерирована.
91..99 Специальные ошибки кода приложения (резерв).
100..599 HTTP коды ответа
700..799 Ошибки кода приложения. С помощью этих кодов может реализовываться некоторый функционал, когда окончание работы кода в методе контроллеров происходит, например так: return 701;

Нотификации об ошибках

С помощью Schedule::mail_error(), можно организовать задачу отсылки письма разработчику, если на продакшн возникли ошибки.

Мягкие ошибки приложений, например "404 - страница не найдена", могут быть показаны внутри layout приложений и на DEV и на PROD.

В режиме DEV, при возникновении ошибки, автоматически всплывает popup с инструментами разработчика на странице трассировки с ошибкой. Есть нюанс, связанный с типом протекания скриптов. Если $sky->fly равна нулю, то подразумевается обычное протекание скрипта, который включает шаблон с layout (точнее полная HTML страница). Используются действия в контроллерах с префиксом a_. В этом случае, программист должен определить в layout шаблоне операторы Jet @head(..) в начале и @tail в конце соответственно. Последний помещает собранную трассировку в конце страницы, в скрытом теге DIV.

Для CSN-AJAX запросов, $sky->fly равна HEAVEN::J_ACT. Используются действия в контроллерах с префиксом j_, а трассировка записывается в БД, memory.1. Имеется три ячейки в БД для записи такой трассировки, которые работают по принципу очереди FILO. При ошибках в таких запросах, popup всплывает сразу, как и в предыдущем случае.

Если скрипт обрабатывает не CSN-AJAX (но AJAX) запрос, fetch запрос, API запрос, file download или, например динамически генерирует SVG изображение на backend, которое затем используется в HTML теге <img ... />, $sky->fly равна HEAVEN::Z_ACT, действие в контроллере с префиксом a_, а трассировка в memory.1. Для установки этого значения, обычно, программист должен в коде использовать метод MVC::mime(..). Если возникли ошибки, при таком $sky->fly, flash-нотификация записывается так: SKY::d('err_z_act', time());, а всплывающий popup инструментов разработчика, возникнет только при последующем клике, который позволит это сделать. Это протекшие без ошибок $sky->fly == 0 или $sky->fly == HEAVEN::J_ACT.

Фатальные ошибки для $sky->fly == 0 и на DEV и на PROD отображаются с помощью шаблона Jet "_std.crash", читайте ниже. Только на продакшн не отображается отладочная информация. Есть два типа обработки таких фатальных ошибок. В основном, работает первый вариант, когда при срабатывании класса-потомка Throwable, буфер STDOUT пуст. И второй тип - когда буфер содержит строку, которая может мешать корректной визуализации. В этом случае, для PROD, код Coresky, пытается несколькими способами сделать редирект на страницу http(s)//site.name/_crash для корректного отображения.

Сопутствующие конфигурации

Все переменные ниже, определены в системной конфигурации, см. memory.8. Для управления на продакшн, можно легко организовать веб-интерфейс, использовав класс Root, смотрите main/w2/root.php или изменить значения в БД используя консольную утилиту main/sky:

# посмотреть системную конфигурацию:
>sky m 8

# отключить crash лог:
>sky eval "$sky->s_log_crash = 0;"
Опция Описание
log_crash активация crash лог
log_error активация error лог. Логирует ошибки, в том числе на продакшн, когда SKY::$debug равно нулю (трассировка при этом не собирается)
error_403 использовать код ответа HTTP 403 для exit, die, вместо 404. Для J_FLY всегда остаётся 200. На код ответа throw new Hacker не влияет. В консольных скриптах exit работает без особенностей
empty_die пустой ответ сервера при срабатывании exit, die
gate_404 генерировать мягкую ошибку 404 на продакшн для gate error.
trace_cli включить запись трассировки для консольных скриптов в memory.1
trace_root включить трассировку для профиля root

Представления ошибок

В jet-файле стандартного контроллера main/w2/__std.jet имеется два шаблона для представления ошибок. Первый - "__std._" для представления мягких ошибок внутри layout приложения, например 404 при $sky->fly == 0. Этот же шаблон используется и для представления ошибок, которые прервали плановое выполнение скрипта при $sky->fly == 1. И второй (используется только при $sky->fly == 0) - "__std.crash" для представления ошибок, которые прервали плановое выполнение скрипта (переменные layout, могут быть не подготовлены), например с помощью throw new Hacker или die.

Стандартное представление ошибок, можно переопределить под нужды приложений, в файле с фиксированным именем view/error.jet. В нем необходимо определить два маркера с теми же именами: _ и crash. Для _, дополнительно, можно передать переменные для представления из общего контроллера common_c::error_y(..) или таких же методов из главных (мастер) контроллеров, но только для "мягких" ошибок приложения. В главном шаблоне для визуализации ошибок используется маркер по умолчанию. Это означает, что для любых шаблонов, которые не найдены, будет использован этот шаблон, например при поиске error.703. Но в этом же файле, можно определить шаблоны для конкретных номеров ошибок и тогда, шаблон по умолчанию не будет использован. Приложение может использовать номера ошибок от 700 до 799 для специальных нотификаций, когда из контроллера возвращается например return 700;. Пример файла view/error.jet:

#.jet system errors

#._ main template for errors, magic marker used!
<div style="display:inline-block;width:100%;margin-top:5%">
  <div style="width:90%; margin-left:10%">
    <h1>Page not found</h1>
    <span style="color:silver;font-size:100px">
      {!$sky->error_no!}
    </span>
    @if(isset($var_from_error_y))
      Visualization part from ..::error_y($action)
    ~if
    @view(show_also_some_content_when_error)
  </div>
  <pre>{!$tracing ?? ''!}</pre>
</div>
#._

#._701 _\d\d\d underscore when MVC::instance()->return is true
Some special notification
#._701

#.702 \d\d\d no underscore when MVC::instance()->return is false
Other notification
#.702

#.777._777 don't forget about aliases
Cool !!!
#.777._777

#.crash this template for crashes when `$sky->fly == 0`
<!doctype html>
<html>@php $h1 = SKY::version()['app'][3] ~php
<head>@head()
  <style>body {
    background:url({!PATH!}img/picture.jpg);
    background-size:cover;
    margin:0 10px;
  }
  </style>
</head>
<body style="@unless($tracing)text-align:center;~unless">
  @if($tracing)<h1>HOLE.SKY version {{$h1}}</h1>~if
  @inc(__std.inner)
  @if($tracing)<h1>HOLE.SKY version {{$h1}}</h1>~if
</body>
</html>
#.crash

Также для продакшн, можно сгенерировать файл var/mem/error.html, включающий визуализацию layout для веб сайта. В этом случае, вместо использования шаблона error.crash, для вывода сообщений о фатальных ошибках, при $sky->fly == 0, будет выведено содержимое этого HTML-файла. Для генерации файла на продакшн, можно использовать класс Root. Смотрите пример использования в инструментах разработчика DEV.

⚠️ **GitHub.com Fallback** ⚠️