这份风格指南的目的是在 PostgreSQL 生成的所有消息中保持一种 一致的、对用户友好的风格。
主要消息应当简短、实事求是,并避免提及实现细节(例如具体的函数 名)。 “简短”的意思是 “在正常条件下应当能放进一行”。 如果需要让主要消息保持简短,或者您觉得有必要提及实现细节 (例如失败的特定系统调用),就使用一条 detail 消息。 主要消息和 detail 消息都应当实事求是。 对于如何修复问题的建议使用 hint 消息,尤其是当该建议可能并非在 所有情况下都适用时。
例如,与其写:
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.
理由:保持主要消息简短有助于它切中要点,并允许客户端在 “一行对错误消息就足够了”的假设下安排屏幕空间。 detail 和 hint 消息可以被放到详细模式中,或者放到一个弹出的错误 细节窗口中。 此外,为了节省空间,detail 和 hint 通常会在服务器日志中被抑制。 最好避免提及实现细节,因为不应指望用户了解这些细节。
不要把关于格式的任何特定假设写进消息文本中。 应当预期客户端和服务器日志会按自己的需要折行。 在长消息中,换行字符(\n)可以用来指示建议的段落分隔。 不要以换行结束消息。 不要使用制表符或其他格式化字符。 (在错误上下文显示中,会自动添加换行来分隔不同层级的上下文, 例如函数调用。)
理由:消息不一定显示在终端类显示器上。 在 GUI 显示或浏览器中,这些格式指示充其量会被忽略。
在适合加引号的地方,英文文本应当使用双引号。 其他语言的文本应当一致地使用一种引号,与出版惯例和其他程序的 计算机输出保持一致。
理由:选择双引号而非单引号多少有些武断,但它往往是首选用法。 有人建议按照 SQL 约定根据对象类型选择引号种类 (即字符串用单引号,标识符用双引号)。 但这是许多用户甚至都不熟悉的语言内部技术问题,它无法推广到 其他种类的被引用术语,也无法翻译成其他语言,而且它也相当 没有意义。
对于文件名、用户提供的标识符、配置变量名以及其他可能包含单词的 变量,始终使用引号定界。 对于不会包含单词的变量(例如操作符名),不要用引号标记它们。
后端中有一些函数会按需对自己的输出加上双引号
(例如,format_type_be())。
不要在这类函数的输出外面再加引号。
理由:对象的名字嵌入消息中时可能产生歧义。 要一致地表明插入的名字从哪里开始和结束。 但不要用不必要或重复的引号弄乱消息。
主要错误消息与 detail/hint 消息的规则不同:
主要错误消息:不要把首字母大写。 不要以句号结束消息。 更不要想用感叹号结束消息。
Detail 和 hint 消息:使用完整的句子,并且每句以句号结束。 把句子的第一个词大写。 如果后面还有另一句,句号后面放两个空格 (对英文文本而言;在其他语言中可能不合适)。
错误上下文字符串:不要把首字母大写,也不要以句号结束字符串。 上下文字符串通常不应是完整的句子。
理由:避免标点让客户端应用程序更容易把消息嵌入到各种语法上下文 中。 主要消息往往本来就不是一个语法完整的句子。 (而且如果它们长到超过一句,就应当被拆分为主要部分和 detail 部分。) 不过,detail 和 hint 消息更长,可能需要包含多个句子。 为了保持一致,即使只有一句话,它们也应当遵循完整句子的 风格。
使用主动语态。 当存在动作主体时使用完整的句子 (“A 无法做 B”)。 如果主体会是程序本身,则使用没有主体的电报风格;不要用 “I” 指代程序。
理由:程序不是人。不要假装它是。
如果做某件事的尝试失败了、但下次也许能成功(也许在修复某个问题 之后),使用过去时。 如果失败肯定是永久性的,使用现在时。
下面这种形式的句子与另一种之间存在着重要的语义差别:
could not open file "%s": %m
和:
cannot open file "%s"
第一种表示打开文件的尝试失败了。 消息应当给出原因,例如 “disk full” 或 “file doesn't exist”。 过去时是恰当的,因为下次磁盘可能就不再满了,或者相关文件可能就 存在了。
第二种形式表明打开指定文件的功能在程序中根本不存在,或者在概念上 不可能。现在时是恰当的,因为这种情况会无限期地持续下去。
理由:诚然,普通用户无法仅从消息的时态得出什么重大结论,但既然 语言为我们提供了语法,我们就应当正确地使用它。
当消息包含在别处生成的文本时,用这种风格嵌入它:
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
如果确实看起来必要,把系统调用放进 detail 消息。 (在某些情况下,为 detail 消息提供传给系统调用的实际值可能是 恰当的信息。)
理由:用户不知道所有这些函数都是做什么的。
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” 听起来软弱,并且会把问题搅浑。
May vs. Can vs. 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”。
请记住,错误消息文本需要被翻译成其他语言。 遵循 Section 56.2.2 中的指南,避免让译者的生活 变得困难。