# 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

写:基本原理:保持主要消息简短有助于保持重点,并让客户端在假设一行足以显示错误消息的情况下布置屏幕空间。详细信息和提示消息可以降级为详细模式,或者可能是弹出错误详细信息窗口。此外,通常会从服务器日志中抑制详细信息和提示以节省空间。

# 最好避免参考实现细节,因为用户不应该知道细节。

格式化不要将任何关于格式的特定假设放入消息文本中。期望客户端和服务器日志换行以满足他们自己的需要。在长消息中,换行符 (\n) 可用于指示建议的分段符。不要以换行符结束消息。不要使用制表符或其他格式字符。

(在错误上下文显示中,换行符会自动添加到单独的上下文级别,例如函数调用。)理由:消息不一定显示在终端类型的显示器上。

# 在 GUI 显示或浏览器中,这些格式说明最多被忽略。

引号当引用适当时,英文文本应使用双引号。

其他语言的文本应始终使用一种与其他程序的发布习惯和计算机输出一致的引号。理由:选择双引号而不是单引号有些随意,但往往是首选用途。有人建议根据 SQL 约定(即字符串单引号、标识符双引号)根据对象类型选择引号类型。

# 但这是许多用户甚至不熟悉的语言内部技术问题,它不会扩展到其他类型的引用术语,它不会翻译成其他语言,而且它也毫无意义。

报价的使用始终使用引号来分隔文件名、用户提供的标识符和其他可能包含单词的变量。

不要使用它们来标记不包含单词的变量(例如,运算符名称)。后端中有一些函数会根据需要对自己的输出进行双引号(例如,format_type_be())。

不要在这些函数的输出周围加上额外的引号。基本原理:对象的名称在嵌入到消息中时可能会产生歧义。在表示插件名称的开始和结束位置时要保持一致。

# 但是不要用不必要的或重复的引号将消息弄乱。

语法和标点

主要错误消息和详细/提示消息的规则不同:主要错误消息:不要将第一个字母大写。不要以句点结束消息。

甚至不要考虑用感叹号结束消息。详细信息和提示信息:使用完整的句子,并以句号结尾。句子的第一个单词大写。如果后面有另一个句子,则在句点后放置两个空格(对于英文文本;在其他语言中可能不合适)。

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

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

# 大写与小写使用小写的消息措辞,包括主要错误消息的第一个字母。

如果 SQL 命令和关键字出现在消息中,请使用大写。

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

# 避免被动语态

使用主动语态。当有表演主语(“A不能做B”)时,使用完整的句子。如果主题是节目本身,则使用不带主题的电报形式;不要在程序中使用“I”。

理由:该程序不是人类的。别装成别的样子。

# 现在时态与过去时态

如果尝试做某事失败了,但下次可能会成功(可能是在解决了一些问题之后),请使用过去式。如果失败肯定是永久性的,则使用现在时态。

这种形式的句子之间有一个重要的语义差异:

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.存在。**如果程序使用一个非平凡的算法来定位资源(例如,路径搜索),但该算法失败,那么可以公平地说,程序无法“找到”资源。另一方面,如果资源的预期位置已知,但程序无法在那里访问它,则表示该资源“不存在”。在这种情况下使用“find”听起来很弱,并且混淆了这个问题。

五月对五月对五月。“May”表示允许(例如,“你可以借用我的耙子。”),在文档或错误消息中几乎没有用处。“Can”表示能力(例如,“我能举起那根木头。”),“may”表示可能性(例如,“今天可能下雨”)。使用合适的词可以澄清意思并帮助翻译。

**收缩。**避免宫缩,比如“不能”;用“不能”代替。

**非阴性。**避免使用“非负”,因为它不确定是否接受零。最好使用“大于零”或“大于或等于零”。

# 正确拼写

完整地拼写单词。例如,避免:

  • 规格

  • 统计数据

  • 帕伦斯

  • 认证

  • xact

    理由:这将提高一致性。

# 本地化

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