支持的版本: 当前 (17) / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 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. 可能。 可以 暗示许可(例如,“你可以借用我的耙子”),在文档或错误消息中很少使用。 暗示能力(例如,“我能举起那根木头”),而 可能 暗示可能性(例如,“今天可能会下雨”)。 使用正确的词可以澄清含义并有助于翻译。

缩略形式。 避免使用缩略形式,例如 不能; 请使用 不能够 代替。

非负。 避免使用 非负,因为它对于是否接受零存在歧义。最好使用 大于零大于或等于零

正确的拼写 #

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

  • spec (规范)

  • stats (统计)

  • parens (括号)

  • auth (授权)

  • xact (事务)

理由:这将提高一致性。

本地化 #

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

提交更正

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