提供这份风格指南,是希望在 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” 几乎就是被动语态。更好的做法是视情况使用 “cannot” 或 “could 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 zero” 或 “greater than or equal to zero”。
单词应完整拼写。例如,避免使用:
spec
stats
parens
auth
xact
原理:这会提升一致性。
请记住,错误消息文本需要被翻译成其他语言。请遵循 Section 54.2.2 中的指导,避免给翻译者制造麻烦。