选择 打开 改范围 完整检索页
受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10
当前 PostgreSQL 版本不在支持生命周期内。
您可以参阅当前版本的对应页面,或其他在上面列出的活跃大版本。

53.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 could not do 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

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

原理:用户并不知道那些函数都做了什么。

应避免的词语

Unable.  Unable 几乎就是被动语态。更好的做法是视情况使用 cannotcould not

Bad. bad result 这样的错误消息,实在很难被合理理解。 最好写出结果为什么是 bad,例如 invalid format

Illegal.  Illegal 指的是违法,其余情况应使用 invalid。 更好的是,直接说明为什么无效。

Unknown.  尽量避免 unknown。考虑 error: unknown response。如果你都不知道响应是什么,又如何知道它有错? Unrecognized 往往是更好的选择。此外,一定要包含被抱怨的值。

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

Find vs. Exists.  如果程序为了定位某个资源使用了非平凡算法(例如路径搜索),而该算法失败了, 那么说程序没能 find 该资源是公平的。另一方面,如果资源的预期位置已知, 但程序无法在那里访问它,那么就应说该资源并不 exist。 在这种情况下使用 find 显得含糊,也会混淆问题。

May、Can 与 Might.  May 暗示许可(例如,"You may borrow my rake."), 在文档或错误消息中用途不大。Can 暗示能力 (例如,"I can lift that log."),而 might 暗示可能性 (例如,"It might rain today.")。使用恰当的词能澄清含义,也有助于翻译。

Contractions.  避免使用缩略形式,例如 can't;应改用 cannot

Non-negative.  避免使用 non-negative,因为它是否接受零有歧义。更好的是使用 greater than zerogreater than or equal to zero

完整拼写

单词应完整拼写。例如,避免使用:

  • spec

  • stats

  • parens

  • auth

  • xact

原理:这会提升一致性。

本地化

请记住,错误消息文本需要被翻译成其他语言。请遵循 Section 54.2.2 中的指导,避免给翻译者制造麻烦。