53.2. Сообщение об ошибках внутри сервера#
53.2. Сообщение об ошибках внутри сервера #
Сообщения об ошибках, предупреждения и журналы, создаваемые внутри кода сервера, должны быть созданы с использованием функции 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. [16]%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- это целочисленное значение, которое определяет, какая форма множественного числа требуется, а остальные аргументы форматируются в соответствии с выбранным форматирующим строкой. Дополнительную информацию см. Раздел 54.2.2.Функция
errdetail(const char *msg, ...)предоставляет необязательное сообщение “detail”; используется, когда есть дополнительная информация, которая кажется неподходящей для размещения в основном сообщении. Строка сообщения обрабатывается так же, как и дляerrmsg.errdetail_internal(const char *msg, ...)то же самое что иerrdetail, за исключением того, что строка сообщения не будет переведена и не будет включена в словарь интернационализации сообщений. Это следует использовать для детальных сообщений, на которые не стоит тратить усилия на перевод, например, потому что они слишком технические, чтобы быть полезными для большинства пользователей.errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)похож наerrdetail, но с поддержкой различных форм множественного числа сообщения. Дополнительную информацию см. в Раздел 54.2.2.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, но с поддержкой различных форм множественного числа сообщения. Дополнительную информацию см. в Раздел 54.2.2.errhint(const char *msg, ...)предоставляет необязательное сообщение “подсказки”; это используется для предложения рекомендаций по исправлению проблемы, в отличие от фактических деталей о том, что пошло не так. Строка сообщения обрабатывается так же, как и дляerrmsg.errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n, ...)похож наerrhint, но с поддержкой различных форм множественного числа сообщения. Дополнительную информацию см. в Раздел 54.2.2.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:сообщения в журнале постмастера. Это следует использовать только для отладочных сообщений с подробным выводом, где повторное включение контекста приведет к раздутию журнала.
Примечание
Максимум одна из функций errtable,
errtablecol, errtableconstraint,
errdatatype или errdomainconstraint должна
использоваться в вызове ereport. Эти функции существуют для
того, чтобы приложения могли извлекать имя объекта базы данных, связанного
с условием ошибки, не просматривая потенциально локализованный текст сообщения об ошибке.
Эти функции следует использовать в отчетах об ошибках, для которых вероятно,
что приложения захотят иметь автоматическую обработку ошибок. Начиная с
PostgreSQL 9.3, полное покрытие существует только для
ошибок в классе SQLSTATE 23 (нарушение целостности ограничений), но это
вероятно будет расширено в будущем.
Есть старая функция elog, которая до сих пор широко используется.
Вызов elog:
elog(level, "format string", ...);
точно равнозначно:
ereport(level, errmsg_internal("format string", ...));
Обратите внимание, что код ошибки SQLSTATE всегда устанавливается по умолчанию, и строка сообщения не подлежит переводу.
Поэтому функция elog должна использоваться только для внутренних ошибок и отладочного журналирования на низком уровне. Любое сообщение, которое, вероятно, будет интересно обычным пользователям, должно проходить через функцию ereport. Тем не менее, в системе достаточно внутренних проверок “недопустимых” ошибок, поэтому функция elog все еще широко используется; она предпочтительна для таких сообщений из-за простоты обозначения.
Советы по написанию хороших сообщений об ошибках можно найти в Раздел 53.3.
[16]
То есть, это значение, которое было актуальным, когда был выполнен вызов ereport;
изменения errno во вспомогательных процедурах отчетности не повлияют на него. Это не будет верным, если бы вы явно написали strerror(errno) в списке параметров errmsg;
соответственно, не делайте этого.