Ошибки
Введение
В библиотеках COREmanager мы активно используем механизм исключений (exception). Архитектура системы подразумевает высокую вложенность вызовов, а исключения — простой способ доставить информацию об ошибке. При написании собственных компонентов стоит придерживаться следующих правил:
- Никогда не подавляйте исключения возникшие при внутренних вызовах isp_api::InternalCall. Это может привести систему в нестабильное состояние. Так как часть операций по обработке запроса может быть выполнена не полностью. Если вы обнаружили ошибку, но все же хотите попробовать выполнить запрос до конца — лучше воспользоваться механизмом повторного выполнения запроса isp_api::RestartRequest.
- Никогда не перехватывайте исключения без определения типа catch (…) или выкидывайте это же исключение наружу throw /* без параметров /;
- Всегда передавайте язык или сессию при внутренних или внешних запросах. Это позволит вам получить сообщение об ошибке в локализованном виде.
Типы исключений
Исключения в библиотеках COREmanager можно разделить по алгоритму их обработки на следующие типы:
Исключения mgr_err::Error
Почти все исключения в библиотеках COREmanager — исключения типа mgr_err::Error . Этот тип исключений унаследован от std::exception. Так что, если вы хотите перехватить все исключения, лучше перехватывать mgr_err::Error или std::exception. В COREmanager мы не используем типизацию исключений. Во первых, исключения могут возникать при удаленных запросах, а их сериализация и десериализация в этом случае не всегда возможна (локальная версия COREmanager, получившая ислючение от удаленного сервиса, может просто не содержать требуемого класса исключений). Во вторых, как показывает практика, довольно редко возникает необходимость в типизации исключений (99% всех catch — это catch(const mgr_err::Error &) или catch(const std::exception &)).
Этот класс содержит состояние стека на момент возникновения исключения и xml документ описывающий тип исключения.
Пример Xml:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<error type="xml" object="xpath" report="yes" lang="ru">
<param name="object" type="msg" msg="Ошибка в XPath '__value__'">xpath</param>
<param name="value">bad XPath</param>
<stack>
<action level="30" user="root">xmlerror</action>
</stack>
<group>Возникла ошибка при работе с XML документом. __object__</group>
<msg>Возникла ошибка при работе с XML документом. Ошибка в XPath 'bad XPath'</msg>
</error>
</doc>
Атрибуты и дочерние узлы узла error:
атрибут external Значение «yes» говорит о том, что исключение было получено от удаленного сервиса. Такие исключения не проходят специальной обработки.
атрибут report Значение «yes» говорит о том, что необходимо сформировать отчет для разработчиков. Такие исключения не должны доходить до пользователя, но, если они все же дойдут, пользователю предложат сообщить о таком случае разработчикам продукта.
атрибут help Если указан, к сообщению об ошибке будет добавлена ссылка на документацию. Имя статьи будет взято из значения атрибута.
атрибут type Тип исключения — произвольная строка. Используется при локализации.
атрибут lang Язык, который был использован для локализации.
атрибут object Значение параметра object
атрибут value Значение параметра value
узел param Параметр исключения. Он, в свою очередь, имеет атрибуты @name — имя параметра, @type — тип параметра (для параметров требующих локализации должен иметь значение «msg»), @msg — локализованное значение параметра. Значение параметра берется из содержимого узла.
узел stack Стек вызовов isp_api::InternalCall на момент возникновения исключения. Каждый дочений узел action содержит атрибуты @level и @user — уровень доступа и имя пользователя с правами которого выполнялось действие. Имя функции записано в содержимом узла action.
узлы detail, group и default локализованное описание исключения.
узел msg скомпанованное локализованное описание исключения.
Локализация
Классы исключений
Не смотря на то, что мы не используем типизацию исключений, не все исключения обрабатываются одинаково. В библиотеках COREmanager деление исключений основывается на атрибутах узла error. По типу обработки можно выделить следующие группы:
Ошибки функций (локальные ошибки) Это ошибки возникающие из-за неверной настройки системы или неверно введенных параметрах. Такие ошибки должны быть максимально понятны конечному пользователю.
Специальные ошибки Очень похожи на ошибки из предыдущей группы. Но их обработка отличается. Примером такой ошибки может быть ошибка типа notconfigured. В случае, если запрос был через API (out=xml), эта ошибка вернется пользователю так же, как и ошибки из первой группы. Но в случае, если эта ошибка возникнет при обращении к панели через web интерфейс, пользователь увидит форму с предложением заполнить недостающие данные. Еще к этой группе можно отнести ошибки авторизации, в случае возникновения которых в web интерфейсе, пользователя перенаправляют на форму регистрации.
Ошибки библиотек Это могут быть как ошибки вызваные нехваткой ресурсов, так и алгоритмические ошибки, когда программист некорректно использует какие-либо библиотечные функции. Таких ошибок быть не должно. А их возникновение приводит к формированию отчета, который будет предложено отправить разработчику. (атрибут report).
Ошибки от удаленных сервисов Это ошибки пришедшие от удаленных сервисов, работающих на базе COREmanager. Могут иметь xml аналогичный ошибкам из любой другой группы. Но никакой специальной обработки такие ошибки не проходят. (атрибут external)
Служебные исключения
Помимо mgr_err::Error COREmanager использует ряд исключений, не унаследованных ни от mgr_err::Error, ни от std::exception. Такие ошибки не должны перехватываться пользотелем никогда.
Assert критическая ошибка. Это тот класс ошибок, которые не должны возникать никогда. Но если она возникла, дальнейшее выполнение приложения бессмысленно или даже опасно. Данный тип исключений порождается макросом ASSERT . В отличии от стандартного Assert наш не завершает выполнение приложения а приводит к завершению выполнения текущего потока. При этом COREmanager предпримет попытку откатить все изменения сделанные в процессе выполнения запроса.
Restart требование повторить выполнения запроса заново. Этот тип исключений используется функцией isp_api::RestartRequest
Skip сообщает о том, что в дальнейшей обработке запроса нет необходимости. Пользователь получит ответ в том виде, в котором он был на момент возникновения этого исключения
Локализация ошибок
Локализация ошибки может зависеть от уровня доступа пользователя, который ее увидит. Для этого вначале идет поиск сообщения с суффиксом __XX, где XX — число, минимальный уровень доступа, который должен иметь пользователь, чтобы его увидеть. Если подходящего сообщения не найдено, используется сообщение без суффикса.
Например, пользователь с уровнем доступа 16 получает ошибку, для локализации которой может быть использовано сообщение с именем*msg_error_some_error*. Вначале будут последовательно проверены сообщения с именами от*msg_error_some_error16*до*msg_error_some_error1*. Если ни одно из них не будет найдено, будет использовано сообщение с именем*msg_error_some_error*.
В случае, если пользователь работает под аккаунтом другого пользователя (функция su), уровень доступа для формирования сообщения об ошибке будет взят у первого пользователя в цепочке (у того, которым он зашел в панель). Таким образом, администратор, работающий с правами пользователя и пользователь, вошедший в панель управления самостоятельно, могут видеть различные сообщения для одних и тех же ошибок
При локализации ошибки COREmanager пытается найти соответствующие сообщения перебирая секции сообщений в следующем порядке:
- msgerror_<тип ошибки>
- Все секции сообщений функций начиная с последней (функции, выполнение которой вызвало ошибку). Таких секций может быть несколько, если ошибка возникла при внутреннем вызове isp_api::InternalCall
- msgerror
В этих секциях COREmanager будет искать сообщения соответствующие значениям параметров с типом msg. И сообщение с именами:
- msg_error_<тип>_<объект>
- msg_error_<тип>
-
msg_error_unknown
Для формирования сообщения, которое увидит пользователь, будет взято наиболее подходящее (msg_error_<тип>_<объект> имеет наивысший приоритет) Затем, в полученной строке будут заменены все подстроки __<имя>__ соответствующие параметрам с типом msg на их локализованнное значение. А затем, все подстроки __<имя>__ соответсвующие остальным параметрам.
Например, при работе со встроенными механизмами баз данных (mgr_db::Cache) в случае, если не удалось добавить запись в базу данных по причине того, что такая запись уже существует, возникнет ошибка с типом «exists», объект будет содержать имя таблицы базы данных, значение — значения дублирующихся полей, разделенные запятой, а также дополнительный параметр «cols», содержащий имена дублирующихся полей (разделенные запятой). Чтобы локализовать такую ошибку, создайте сообщение типа:
msg_error_exists_<имя_таблицы>
А текст сообщения может иметь следующий вид: __cols__ со значением __value__ уже существует.
![]() |
![]() |
Детали файла
| Имя файла: | 5312.02.01;МТ.01;2 |
| Размер: | 104 Kb |
| Дата публикации: | 2015-03-09 04:45:24 |
| Описание: | |
| Технология составления бухгалтерской отчетности (СП) — Модульный тест
Список вопросов теста (скачайте файл для отображения ответов): Верны ли определения: |
|
| Для скачивания этого файла Вы должны ввести код указаный на картинке справа в поле под этой картинкой —> | |
| ВНИМАНИЕ: | |
| Нажимая на кнопку «Скачать бесплатно» Вы подтверждаете свое полное и безоговорочное согласие с «Правилами сервиса» | |
The truncation error does not satisfy that equation, it’s just its definition.
Consider two following problems:
- The first is an ODE.
$$
y'(t) = f(t, y(t))\
y(0) = a.
$$
Its solution is some smooth function $y(t)$. - The second is a difference equation
$$
frac{z_{i+1} — z_i}{h} = f(t_i, z_i)\
z_0 = a.
$$
Its solution is some discrete function $z_i$.
I’ve intentionally used different letters to denote those two solutions. They are quite different, the former is a smooth function while the latter is a discrete one. One needs to be careful even to compare those two. Usually the third function is introduced. It is defined as a restriction of the smooth $y(t)$ to the grid $t_i$, where the discrete function $z_i$ is defined. Let’s denote the restriction as $w_i$:
$$
w_i equiv y(t_i).
$$
The function $w_i$ is discrete just like $z_i$ and $w_i$ coincide with $y(t)$ at grid points. Since now $w_i$ and $z_i$ are functions of the same class we can easily compare them:
$$
e_i = w_i — z_i equiv y(t_i) — z_i.
$$
So, roughly speaking, the global error shows how close are $y(t)$ and $z_i$ (by restricting the former to the grid). When someone is solving some problem numerically the global error is what he is interesting in. Anyway, direct computation of global error is almost impossible, since we often simply do not have the exact values of $w_i = y(t_i)$ (
in contradistinction to $z_i$, which we can compute easily).
And the local truncation error concept comes to the rescue. Note that previously we’ve compared the solutions. Now we’re going to compare problems. Take $z_i$. It is the solution to the second problem. Plugging $z_i$ into it makes it a valid identity
$$
frac{z_{i+1} — z_i}{h} = f(t_i, z_i)\
z_0 = a.
$$
But if we now take $w_i$ and try to plug it into the difference scheme we wont get an identity. Instead we’ll get a residual:
$$
frac{w_{i+1} — w_i}{h} = f(t_i, w_i) color{red}{{}+ d_i}\
w_0 = a color{red}{{} + d_0}.
$$
If we are very lucky, some residuals may vanish, like $d_0$, but often it is not the case.
So why is $d_i$ interesting while it also is defined in terms of $w_i$ (the unknown solution to the original problem)? It turns out that we can estimate the $d_i$ without knowing the exact values of $w_i$ by just knowing the original problem.
$$
d_i = frac{w_{i+1} — w_i}{h} — f(t_i, w_i) equiv
frac{y(t_{i+1}) — y(t_i)}{h} — f(t_i, y(t_i)) = \ =
y'(t_i) + h frac{y»(t_i)}{2} + O(h^2) — f(t_i, y(t_i)) = \ =
color{blue}{left[y'(t_i) — f(t_i, y(t_i))right]} + color{red}{h frac{y»(t_i)}{2} + O(h^2)}
$$
The blue term in braces is exactly the original ODE, and $y(t)$ is exactly its solution. So the term is equal to zero.
$$
d_i = h frac{y»(t_i)}{2} + O(h^2).
$$
Similar result may be obtained if using different form of Taylor’s formula:
$$
d_i = h frac{y»(xi_i)}{2}, qquad xi_i in [t_{i}, t_{i+1}].
$$
So now we can estimate the local truncation error, but we’re interested in the global error.
To relate them we need to introduce another concept of stability. Consider the two discrete problems
$$
begin{aligned}
&frac{z_{i+1} — z_i}{h} = f(t_i, z_i)\
&z_0 = a
end{aligned}
qquadtext{and}qquad
begin{aligned}
&frac{w_{i+1} — w_i}{h} = f(t_i, w_i) color{green}{{} + d_i}\
&w_0 = a color{green}{{} + d_0}
end{aligned}.
$$
Pretend that we know $d_i$. Let’s view the second problem as a perturbation of the first one. That’s reasonable, since $d_i$ is a small value of $O(h)$ magnitude. A difference problem is called stable if such small perturbations result in small changes of the solution. For this case this means that the difference $z_i — w_i$ will also be small. Precisely
$$
max_i |z_i — w_i| leq C max_i |d_i|
$$
where $C$ is called the stability constant of the method. For the explicit Euler method it can be shown that for Lipschitz-continuous $f$
$$
C leq e^{LT}
$$
with $L$ being the Lipschitz constant of $f$ and $T$ is the total integration time $T = max_i t_i$.
Finally we can relate the global error and the local truncation error by
$$
|e_i| leq C max_i |d_i|
$$
If the local truncation error tends to zero when the discrete mesh is refined the numerical method is called consistent. The Lax theorem states that a stable consistent method converges, in sense that $e_i to 0$ when the mesh is refined.


