56.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”)。如果主语是程序本身,则使用不带主语的电报风格;不要为程序使用“我”。
基本原理:程序不是人。不要假装是人。
现在时与过去时#
如果尝试执行某项操作失败,但下次(可能在解决某些问题后)可能会成功,则使用过去时。如果失败肯定永久存在,则使用现在时。
形式为的句子之间存在非平凡的语义差异
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
**查找与存在。**如果程序使用非平凡算法来查找资源(例如,路径搜索),并且该算法失败,那么可以说该程序无法“查找”该资源。另一方面,如果已知资源的预期位置,但程序无法在那里访问它,那么可以说该资源不存在“存在”。在这种情况下使用“查找”听起来很牵强,并且会混淆问题。
可能与可以与也许。“可能”表示许可(例如,“你可以借用我的耙子。”),在文档或错误消息中几乎没有用。“可以”表示能力(例如,“我可以抬起那根原木。”),而“也许”表示可能性(例如,“今天可能会下雨。”)。使用正确的单词可以阐明含义并帮助翻译。
**缩写。**避免使用缩写,例如“不能”;改用“不能”。
**非负。**避免使用“非负”,因为它对于是否接受零含糊不清。最好使用“大于零”或“大于或等于零”。
正确的拼写#
将单词拼写完整。例如,避免
spec
stats
parens
auth
xact
理由:这将提高一致性。
本地化#
请记住,错误消息文本需要翻译成其他语言。遵循第 57.2.2 节中的准则,避免给翻译人员造成困难。