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
;
соответственно, не делайте этого.