2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4

54.3. 错误消息风格指南 #

本风格指南旨在帮助维护 PostgreSQL 生成所有消息的一致且用户友好的风格。

内容安排 #

主要消息应简短、准确,避免引用实现细节,例如特定的函数名称。 “简短”意味着“在正常情况下应在一行内显示”。如果需要缩短主要消息,或者您需要提及实现细节(例如失败的特定系统调用),请使用详细信息消息。主要消息和详细信息消息都应是事实性的。对于有关如何解决问题的建议,请使用提示消息,尤其是在建议可能并不总是适用时。

例如,不要写:

IpcMemoryCreate: shmget(key=%d, size=%u, 0%o) failed: %m
(plus a long addendum that is basically a hint)

而要写:

Primary:    could not create shared memory segment: %m
Detail:     Failed syscall was shmget(key=%d, size=%u, 0%o).
Hint:       The addendum, written as a complete sentence.

理由:保持主要消息简短有助于使其切中要害,并允许客户端在假设一行足以显示错误消息的情况下布局屏幕空间。详细信息和提示消息可以降级到详细模式,或者可能是弹出错误详细信息窗口。此外,详细信息和提示通常会从服务器日志中抑制以节省空间。最好避免引用实现细节,因为用户不希望了解这些细节。

格式 #

不要在消息文本中添加任何关于格式的特定假设。期望客户端和服务器日志会根据自己的需要换行。在长消息中,可以使用换行符 (\n) 来指示建议的段落分隔符。不要以换行符结束消息。不要使用制表符或其他格式字符。(在错误上下文显示中,会自动添加换行符以分隔函数调用等上下文级别。)

理由:消息不一定会显示在终端类型的显示器上。在 GUI 显示器或浏览器中,这些格式说明充其量会被忽略。

引号 #

英语文本在需要引用时应使用双引号。其他语言的文本应始终如一地使用一种与出版习俗和其它程序的计算机输出一致的引号。

理由:选择双引号而不是单引号在某种程度上是任意的,但往往是首选用法。有些人建议根据 SQL 约定(即字符串用单引号括起来,标识符用双引号括起来)根据对象类型选择引号类型。但这只是一个语言内部的技术问题,许多用户甚至不熟悉它,它无法扩展到其他类型的带引号的术语,它无法翻译成其他语言,而且它也没有什么意义。

引号的使用 #

始终使用引号来分隔文件名、用户提供的标识符、配置变量名称和其他可能包含单词的变量。不要使用它们来标记不会包含单词的变量(例如,运算符名称)。

后端有一些函数会根据需要双引号输出(例如,format_type_be())。不要在这些函数的输出周围添加额外的引号。

理由:对象可以具有在嵌入消息时产生歧义的名称。在表示插入的名称的开始和结束位置时要保持一致。但不要用不必要或重复的引号使消息混乱。

语法和标点符号 #

主要错误消息和详细信息/提示消息的规则不同

主要错误消息:不要将第一个字母大写。不要以句点结束消息。甚至不要考虑以感叹号结束消息。

详细信息和提示消息:使用完整的句子,并在每个句子末尾加上句点。将句子的第一个单词大写。如果后面跟着另一个句子,则在句点后加两个空格(对于英语文本;在其他语言中可能不合适)。

错误上下文字符串:不要将第一个字母大写,也不要以句点结束字符串。上下文字符串通常不应该是完整的句子。

理由:避免标点符号使客户端应用程序更容易将消息嵌入到各种语法上下文中。通常,主要消息本身也不是完整的语法句子。(如果它们足够长以至于超过一个句子,则应将其拆分为主要部分和详细信息部分。)但是,详细信息和提示消息更长,可能需要包含多个句子。为了保持一致性,即使只有一个句子,也应该遵循完整句子的风格。

大写和小写 #

对于消息措辞使用小写,包括主要错误消息的第一个字母。如果 SQL 命令和关键字出现在消息中,请使用大写。

理由:这样更容易使所有内容看起来更加一致,因为有些消息是完整的句子,而有些则不是。

避免被动语态 #

使用主动语态。如果存在执行主体,则使用完整的句子(“A 无法执行 B”)。如果主体是程序本身,则使用电报风格省略主体;不要使用“我”来指代程序。

理由:程序不是人。不要假装它是。

现在时态与过去时态 #

如果尝试执行某些操作失败,但可能下次会成功(可能在修复某些问题后),则使用过去时态。如果失败肯定是永久性的,则使用现在时态。

以下两种形式的句子之间存在非平凡的语义差异:

could not open file "%s": %m

cannot open file "%s"

第一个句子表示打开文件的尝试失败了。消息应说明原因,例如“磁盘已满”或“文件不存在”。过去时态是合适的,因为下次磁盘可能不再满了,或者相关文件可能存在。

第二种形式表明程序根本不存在打开指定文件的功能,或者它在概念上是不可能的。现在时态是合适的,因为这种情况将无限期地持续下去。

理由:当然,普通用户仅仅根据消息的时态无法得出很好的结论,但既然语言为我们提供了语法,我们就应该正确地使用它。

对象的类型 #

在引用对象名称时,说明该对象的类型。

理由:否则没有人会知道“foo.bar.baz”指的是什么。

括号 #

方括号仅用于 (1) 命令概要中表示可选参数,或 (2) 表示数组下标。

理由:任何其他用法都不对应于广为人知的习惯用法,并且会使人感到困惑。

组装错误消息 #

当消息包含在其他地方生成的文本时,请将其嵌入到此样式中

could not open file %s: %m

理由:很难考虑所有可能的错误代码以将其粘贴到一个流畅的句子中,因此需要某种标点符号。有人建议将嵌入的文本放在括号中,但如果嵌入的文本很可能是消息中最重要的部分,就像通常情况那样,这就不自然了。

错误原因 #

消息应始终说明发生错误的原因。例如

BAD:    could not open file %s
BETTER: could not open file %s (I/O failure)

如果不知道原因,您最好修复代码。

函数名称 #

不要在错误文本中包含报告例程的名称。我们有其他机制可以在需要时找出它,并且对于大多数用户来说,这不是有用的信息。如果错误文本在没有函数名称的情况下没有那么有意义,请重新措辞。

BAD:    pg_strtoint32: error in "z": cannot parse "z"
BETTER: invalid input syntax for type integer: "z"

也避免提及调用的函数名称;相反,说明代码正在尝试执行的操作

BAD:    open() failed: %m
BETTER: could not open file %s: %m

如果确实有必要,请在详细信息消息中提及系统调用。(在某些情况下,提供传递给系统调用的实际值可能是详细信息消息的适当信息。)

理由:用户不知道所有这些函数的作用。

要避免的棘手词语 #

无法。 “无法”几乎是被动语态。最好根据需要使用“不能”或“无法”。

错误。 像“错误结果”这样的错误消息很难进行智能解释。最好写出结果“错误”的原因,例如“无效格式”。

非法。 非法 代表违反法律,其余情况使用 无效。更佳的做法是说明无效的原因。

未知。 尽量避免使用 未知。可以考虑使用 错误:未知响应。如果你不知道响应是什么,你怎么知道它是错误的?无法识别 通常是更好的选择。此外,请务必包含引起错误的值。

BAD:    unknown node type
BETTER: unrecognized node type: 42

查找 vs. 存在。 如果程序使用非平凡的算法来定位资源(例如,路径搜索)并且该算法失败,那么可以公平地说程序无法 找到 该资源。另一方面,如果资源的预期位置已知但程序无法在该位置访问它,则说明该资源不存在 存在。在这种情况下使用 查找 听起来很无力,并且会混淆问题。

可能 vs. 可以 vs. 或许。 可能 表示许可(例如,“您可以借用我的耙子。”),在文档或错误消息中几乎没有用处。 可以 表示能力(例如,“我能够举起那根木头。”),而 或许 表示可能性(例如,“今天可能会下雨。”)。使用正确的词语可以澄清含义并帮助翻译。

缩写。 避免使用缩写,例如 不能;请改用 无法

非负。 避免使用 非负,因为它在是否接受零方面含糊不清。最好使用 大于零大于或等于零

拼写正确 #

将单词完整拼写出来。例如,避免

  • 规范

  • 统计

  • 括号

  • 授权

  • 事务

理由:这将提高一致性。

本地化 #

请记住,错误消息文本需要翻译成其他语言。请遵循 第 55.2.2 节 中的指南,以避免给翻译人员带来困难。

提交更正

如果您在文档中发现任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用 此表单 报告文档问题。