Сообщения об ошибках на сервере
Эта страница переведена при помощи нейросети GigaChat.
Сообщения об ошибках, предупреждения и обычные сообщения, выдаваемые в коде сервера должны создаваться функцией ereport или родственной ее предшественницей elog. Использование этой функции достаточно сложно и требует некоторых пояснений.
Для каждого сообщения есть два обязательных элемента: уровень серьезности (от DEBUG до PANIC) и основной текст сообщения. Кроме того, есть необязательные элементы, наиболее распространенным из которых является код идентификатора ошибки, который соответствует SQL-соглашениям SQLSTATE. Сам ereport - это просто макрос обертки, который существует в основном для синтаксического удобства, чтобы генерация сообщений выглядела как один вызов функции в исходном коде C. Единственный параметр, принимаемый непосредственно ereport, - это уровень серьезности. Основной текст сообщения и любые необязательные элементы сообщения генерируются путем вызова вспомогательных функций, таких как errmsg, внутри вызова ereport.
Типичный вызов ereport может выглядеть следующим образом:
ereport(ERROR,
errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero"));
Это указывает на уровень серьезности ошибки ERROR (обычная ошибка). Вызов errcode задает код ошибки SQLSTATE с помощью макроса, определенного в src/include/utils/errcodes.h. Вызов errmsg предоставляет основной текст сообщения.
Часто можно встретить и более старый стиль, когда вокруг вызовов вспомогательных функций ставятся дополнительные круглые скобки:
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
Дополнительные скобки требовались до PostgreSQL 12, но теперь они не обязательны.
Более сложный пример:
ereport(ERROR,
errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("function %s is not unique",
func_signature_string(funcname, nargs,
NIL, actual_arg_types)),
errhint("Unable to choose a best candidate function. "
"You might need to add explicit typecasts."));
Это иллюстрирует использование кодов формата для вставки значений времени выполнения в текст сообщения. Также предусмотрено необязательное сообщение-подсказка. Вызовы вспомогательных функций могут быть записаны в любом порядке, но по традиции errcode и errmsg появляются первыми.
Если уровень серьезности равен ERROR или выше, ereport прерывает выполнение текущего запроса и не возвращается к вызывающей стороне. Если уровень серьезности ниже ERROR, ereport возвращается в нормальном режиме.
Для ereport доступны следующие вспомогательные процедуры:
errcode(sqlerrcode)указывает код идентификатора ошибки SQLSTATE для состояния. Если эта процедура не вызывается, идентификатор ошибки по умолчанию будетERRCODE_INTERNAL_ERROR, когда уровень тяжести ошибки равен ERROR или выше,ERRCODE_WARNING, когда уровень ошибки равенWARNING, в противном случае (дляNOTICEи ниже)ERRCODE_SUCCESSFUL_COMPLETION. Хотя эти значения по умолчанию часто удобны, всегда думайте, подходят ли они, прежде чем пропускать вызовerrcode();errmsg(const char \*msg, ...)указывает основной текст сообщения об ошибке и, возможно, значения во время выполнения для вставки в него. Вставки определяются кодами формата в стилеsprintf. В дополнение к стандартным кодам формата, принятымsprintf, код формата %m может использоваться для вставки сообщения об ошибке, возвращаемогоstrerrorдля текущего значенияerrno(то есть, значение, которое было текущим, когда был достигнут вызовereport, измененияerrnoв вспомогательных процедурах отчетности не повлияют на него. Это было бы неверно, если бы написалиstrerror(errno) явно в списке параметровerrmsg, соответственно, не делайте этого).%mне требует никакой соответствующей записи в списке параметров дляerrmsg. Обратите внимание, что строка сообщения будет запущена черезgettextдля возможной локализации перед обработкой кодов формата;errmsg_internal(const char \*msg, ...)то же, что и errmsg, за исключением того, что строка сообщения не будет переведена и не будет включена в словарь сообщений интернационализации. Это следует использовать для случаев «невозможно», которые, вероятно, не стоят усилий по переводу;errmsg_plural(const char \*fmt\_singular, const char \*fmt\_plural, unsigned long n, ...)похож наerrmsg, но с поддержкой различных множественных форм сообщения.fmt_singular- формат английского единственного числа,fmt_plural- формат английского множественного числа, n - целочисленное значение, которое определяет, какая форма множественного числа необходима, а остальные аргументы форматируются в соответствии с выбранной строкой формата. Подробнее подробнее смотрите в разделе «Рекомендации по написанию сообщений»;errdetail(const char \*msg, ...)предоставляет дополнительное сообщение «детали», это должно использоваться, когда есть дополнительная информация, которую, кажется, не следует помещать в основное сообщение. Строка сообщения обрабатывается так же, как и дляerrmsg;errdetail_internal(const char \*msg, ...)то же, что и errdetail, за исключением того, что строка сообщения не будет переведена и не будет включена в словарь сообщений интернационализации. Это следует использовать для подробных сообщений, на которые не стоит тратить усилия на перевод, например, потому что они слишком технически сложны, чтобы быть полезными для большинства пользователей;errdetail_plural(const char \*fmt\_singular, const char \*fmt\_plural, unsigned long n, ...)похож наerrdetail, но с поддержкой различных множественных форм сообщения. Подробнее смотрите в разделе Для программистаerrdetail_log(const char \*msg, ...)то же самое, что иerrdetail, за исключением того, что эта строка идет только в журнал сервера, никогда не к клиенту. Если используются как errdetail (или один из его эквивалентов выше), так иerrdetail_log, то одна строка идет к клиенту, а другая - к журналу. Это полезно для деталей ошибок, которые слишком чувствительны к безопасности или слишком громоздки;errdetail_log_plural(const char \*fmt\_singular, const char \*fmt\_plural, unsigned long n, ...)похож наerrdetail_log, но с поддержкой различных множественных форм сообщения. Подробнее подробнее смотрите раздел «Рекомендации по написанию сообщений»;errhint(const char \*msg, ...)предоставляет дополнительное сообщение «подсказка», это должно использоваться при предложении советов о том, как исправить проблему, а не фактических подробностей о том, что пошло не так. Строка сообщения обрабатывается так же, как и дляerrmsg;errhint_plural(const char \*fmt\_singular, const char \*fmt\_plural, unsigned long n, ...)похож наerrhint, но с поддержкой различных множественных форм сообщения. Подробнее подробнее смотрите раздел «Рекомендации по написанию сообщений»errcontext(const char \*msg, ...)обычно вызывается не напрямую с сайта сообщенияereport, скорее, он используется в функциях обратного вызоваerror_context_stackдля предоставления информации о контексте, в котором произошла ошибка, например, текущего местоположения в функцииPL. Строка сообщения обрабатывается так же, как и дляerrmsg. В отличие от других вспомогательных функций, ее можно вызвать более одного раза за вызовereport, последующие строки, предоставляемые таким образом, объединяются с отделяющимися новыми строками;errposition(int cursorpos)определяет текстовое расположение ошибки в строке запроса. В настоящее время он полезен только для ошибок, обнаруженных на этапах лексического и синтаксического анализа обработки запроса;errtable(Relation rel)указывает отношение, имя которого и имя схемы должны быть включены в качестве вспомогательных полей в отчет об ошибке;errtablecol(Relation rel, int attnum)указывает столбец, имя которого, имя таблицы и имя схемы должны быть включены в качестве вспомогательных полей в отчет об ошибке;errtableconstraint(Relation rel, const char \*conname)указывает ограничение таблицы, имя, имя таблицы и имя схемы которого должны быть включены в качестве вспомогательных полей в отчет об ошибке. Индексы должны считаться ограничениями для этой цели, независимо от того, имеют ли они соответствующую запись ограниченияpg_constraint. Будьте осторожны, чтобы передать лежащее в основе отношение кучи, а не сам индекс, какrel;errdatatype(Oid datatypeOid)указывает тип данных, имя которого и имя схемы должны быть включены в качестве вспомогательных полей в отчет об ошибке;errdomainconstraint(Oid datatypeOid, const char \*conname)указывает ограничение домена, имя которого, имя домена и имя схемы должны быть включены в качестве вспомогательных полей в отчет об ошибке;errcode_for_file_access()- это удобная функция, которая выбирает соответствующий идентификатор ошибки SQLSTATE для сбоя в системном вызове, связанном с доступом к файлам. Он использует сохраненныйerrno, чтобы определить, какой код ошибки сгенерировать. Обычно это следует использовать в сочетании с%mв тексте основного сообщения об ошибке;errcode_for_socket_access()- это удобная функция, которая выбирает соответствующий идентификатор ошибки SQLSTATE для сбоя в системном вызове, связанном с сокетами;errhidestmt(bool hide_stmt)можно вызвать, чтобы указать удаление части сообщенияSTATEMENT:в журнале почтмейстера. Обычно это подходит, если текст сообщения уже содержит текущий оператор;errhidecontext(bool hide_ctx)можно вызвать, чтобы указать удаление частиCONTEXT:сообщения в журнале почтмейстера. Это должно использоваться только для громкой отладки сообщений, где повторное включение контекста слишком раздувает журнал.
В вызове ereport должно использоваться не более одной из функций errtable, errtablecol, errtableconstraint, errdatatype или errdomainconstraint. Эти функции существуют, чтобы позволить приложениям извлекать имя объекта базы данных, связанного с условием ошибки, без необходимости проверять потенциально локализованный текст сообщения об ошибке. Эти функции должны использоваться в отчетах об ошибках, для которых приложения, вероятно, хотели бы иметь автоматическую обработку ошибок. Начиная с PostgreSQL 9.3, полное покрытие существует только для ошибок в классе SQLSTATE 23 (нарушение ограничений целостности), но это, вероятно, будет расширено в будущем
Существует более старая функция elog, которая до сих пор широко используется. Вызов elog:
elog(level, "format string", ...);
Это эквивалентно:
ereport(level, errmsg_internal("format string", ...));
Обратите внимание, что код ошибки SQLSTATE всегда используется по умолчанию, а строка сообщения не подлежит переводу. Поэтому elog следует использовать только для внутренних ошибок и журналов отладки низкого уровня. Любое сообщение, которое может представлять интерес для обычных пользователей, должно проходить через ereport. Тем не менее в системе есть достаточно много внутренних проверок для случаев, «которые не должны происходить», и в них по-прежнему широко используется elog, для таких сообщений эта функция предпочитается из-за простоты записи.
Советы по написанию хороших сообщений об ошибках можно найти в разделе «Руководство по стилю сообщения об ошибке»