提供这份风格指南,是希望在 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, written as a complete sentence.
原理:保持主消息简短,有助于使其切中要点,也便于客户端假定一行足以容纳错误消息, 从而安排屏幕空间。详情消息和提示消息可以归入详细模式,或者放到弹出的错误详情窗口中。 此外,为节省空间,详情消息和提示消息通常会从服务器日志中省略。 最好避免提及实现细节,因为用户通常并不了解这些细节。
不要在消息文本中写入任何特定的格式假设。应预期客户端和服务器日志会按照各自需要折行。 对于较长的消息,可以使用换行字符(\n)来表示建议的分段。不要让消息以换行结束。 不要使用制表符或其他格式控制字符。(在错误上下文显示中,会自动添加换行以分隔函数调用等上下文层次。)
原理:消息不一定显示在终端类设备上。在 GUI 显示或浏览器中, 这些格式指令充其量也只是被忽略。
英文文本在适合引用时应使用双引号。其他语言的文本应一致地使用一种引号, 这种引号应符合该语言的出版习惯以及其他程序的计算机输出习惯。
原理:选择双引号而不是单引号多少有些武断,但通常更符合首选用法。 有人建议按照 SQL 约定,根据对象类型来选择引号的种类 (即字符串用单引号,标识符用双引号)。但这是语言内部的技术问题, 很多用户甚至并不熟悉;它也无法扩展到其他类型的被引术语, 更无法翻译到其他语言中,而且本身也没什么意义。
对文件名、用户提供的标识符、配置变量名以及其他可能包含单词的变量, 始终使用引号界定。对于不会包含单词的变量(例如操作符名),则不要加引号。
后端中有些函数会在需要时自行给其输出加上双引号(例如 format_type_be())。不要再对这类函数的输出额外加引号。
原理:对象的名称在嵌入消息时可能造成歧义。对于插入的名称从哪里开始、到哪里结束,要保持一致。 但也不要用不必要或重复的引号把消息弄得杂乱无章。
主错误消息与详情/提示消息的规则不同:
主错误消息:首字母不要大写。消息末尾不要加句号。更不要想着在消息末尾加感叹号。
详情消息和提示消息:使用完整句子,并且每条都用句号结束。句子的第一个词要首字母大写。 如果后面还有一句,在句号后放两个空格(针对英文文本;对其他语言可能并不合适)。
错误上下文字符串:首字母不要大写,字符串末尾不要加句号。上下文字符串通常不应是完整句子。
原理:避免使用标点,能让客户端应用更容易把消息嵌入各种语法上下文中。 主消息往往本来也不是语法完整的句子。(而如果它们长到不止一句, 就应当拆分成主消息和详情消息。)不过,详情消息和提示消息更长, 也可能需要包含多个句子。为了保持一致,即便只有一个句子,它们也应遵循完整句子的风格。
使用主动语态。有施动者时,用完整句子(“A could not do B”)。 如果施动者就是程序本身,则使用无主语的电报式写法,但不要把程序写成 “I”。
原理:程序不是人。不要假装它是。
如果一次尝试做某事失败了,但下次仍可能成功(也许在修复某个问题之后), 就使用过去时。如果失败显然是永久性的,就使用现在时。
下面两种句式在语义上有明显差别:
could not open file "%s": %m
和:
cannot open file "%s"
第一种表示尝试打开文件失败了。消息应给出原因,例如 “磁盘已满” 或 “文件不存在”。过去时更合适,因为下次磁盘可能就不满了, 或者所请求的文件可能已经存在。
第二种形式表示,程序中根本不存在打开该命名文件的功能,或者从概念上就不可能。 现在时更合适,因为这种情况会无限期持续下去。
原理:诚然,普通用户未必能仅凭消息的时态得出什么重要结论, 但既然语言提供了语法,我们就应当正确使用它。
当消息中包含其他地方生成的文本时,应按以下方式嵌入:
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 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 55.2.2 中的指导,避免给翻译者制造麻烦。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。