【译】Python日志最佳实践
原文链接:https://www.cnblogs.com/harrymore/p/16076569.html
如果你和我一样是一个后端开发者,那么日志就是通向你的应用的窗口了。不像前端,后端应用除了日志信息外没多少可以直接看到的东西。以下是我写日志的时候,遵循的一些个人原则。
记在后而非前
想当年,每艘船上都会有一本航海日志,它就如日记一般记录着每天发生的重要事件。就如航海日志那样,我们应该记录已经发生而不是即将要做的事情。
举个例子:
// 错误示例 log.info("Making request to REST API") restClient.makeRequest() // 正确做法 restClient.makeRequest() log.info("Made request to REST API")
第一条日志其实没告诉我们啥东西,如果你读到这条日志,你并不知道REST调用是否成功了,因此你还要去看一下有没有发生异常。如果你读到这条日志并错过后续抛出的异常,相信我,你将懵逼一整天。
第二条日志就好多了。它很清晰的告诉我们前面的操作已经成功执行了。如果REST调用失败了,你也不会看到这条日志,取而代之是一个异常。
这条规则适用于所有INFO级别的日志,DEBUG日志除外。
参数和信息分离
一条典型的日志一般包含两种类型的数据。一种描述当前发生了什么事情。第二种就是在这个操作中涉及到的一系列技术参数。两种信息你最好要分开。
// 错误示例 restClient.makeRequest() log.info("Made request to {} on REST API.", url) // 正确做法 restClient.makeRequest() log.info("Made request to REST API. [url={}]", url)
第一条日志信息是有问题的,它很难通过例如Grok patterns表达式去进行解析。对于日志工具来说,这种日志范式,自动提取id或者其他参数就变得更难了。而且可读性也变差了,试想一下,一个带有一堆参数在后面的超长URL,日志信息的一半就已经超过你的屏幕了。当然,这条日志也变得更难拓展了。如果你想加入其他参数,譬如用到的HTTP方法,你必须重写整个句子。
第二个版本就很好的避开了这些坑。因为参数列表有一个很清晰的格式,所以解析起来是很简单的。而且可读性也变好了,日志前面就是一个完整的句子。扩展也相应变得容易了,你直接把参数加到后面的列表中就可以了。
区分WARNING和ERROR
很明显,日志级别存在是有原因的,所以你需要因地制宜。WARNING和ERROR消息有几个关键的区别。
如果有一些操作,实际上是已经起作用的,但是存在一些小问题,那你就用WARNING。但如果你做了一些操作,跑都没跑起来,那就用ERROR。
看个例子:
try { restClient.makeRequest() log.info("Made request to REST API. [url={}]", url) } catch(e: UnauthorizedException) { log.warn("Request to REST API was rejected because user is unauthorized. [url={}, result={}]", url, result) } catch(e: Exception) { log.error("Request to REST API failed. [url={}, exception={}]", url, exception) }
这个REST调用的结果可能有三种:
- 正常运行,那么用INFO(调用后使用)。
- 运行失败,并抛出了意料外的异常,那么就是ERROR。
- 运行失败,抛出意料中的异常,使用WARNING。
因此,使用WARNING的情况,是你运行了一些东西,但是不是完美完成。使用ERROR的情况,是这个操作就完全没执行完成。
需要注意的是,WARNING(当然ERROR也是)是一个行动倡议(call to action比较难翻译,意思是看到的人需要对这个消息作出一定的响应)。如果没人需要对其作出响应或者做一些相应的事情,那你就不需要用WARNING了。
业务消息用INFO,技术消息用DEBUG
INFO日志应该像一本书,它告诉你发生了什么,而不是怎么发生的。这意味着相比技术相关的日志信息,INFO级别更适合偏业务性的日志信息。涉及技术相关信息最好还是用DEBUG。
INFO | User registered for newsletter. [user="Thomas", email="thomas@tuhrig.de"] INFO | Newsletter send to user. [user="Thomas"] INFO | User unsubscribed from newsletter. [user="Thomas", email="thomas@tuhrig.de"]
这种类型的日志就像从我们的业务的视角给你讲了个故事,那技术相关的日志呢?
DEBUG | Saved user to newsletter list. [user="Thomas", email="thomas@tuhrig.de"] DEBUG | Send welcome mail. [user="Thomas", email="thomas@tuhrig.de"] INFO | User registered for newsletter. [user="Thomas", email="thomas@tuhrig.de"] DEBUG | Started cron job to send newsletter of the day. [subscribers=24332] INFO | Newsletter send to user. [user="Thomas"] INFO | User unsubscribed from newsletter. [user="Thomas", email="thomas@tuhrig.de"]
每条业务用例产生一行INFO日志。相应的,DEBUG日志给出这个过程执行中内部的更多的细节。
其他
当然了,对于好的日志来说还有很多需要注意的。你需要考虑像追踪,日志聚合和指标。但归结到记录日志上面,我真的推荐这些小规则。
致敬
Thomas