【译文】原文地址
你曾经是否遇到过代码发生错误,但不确定具体哪个文件发生的错误?当然我也遇到过。
在实际的开发中,应用包含大量的代码文件,找到错误发生的原因是很耗时间的。经常在开发的过程中,有时为了测试我们对一个有bug的站点发起一个HTTP客户端调用。希望能返回错误的响应,逻辑错误的确发生了,我们需要尽快的修复。
正常情况下开发者将根据客户端调用返回信息第一时间在后台收集错误信息。并对发生根因进行分析,根据错误信息会预测可能发生错误的文件位置、函数和代码行。如果日志信息足够详细将会很容易定位错误发生的位置。否则....
- 检查路由处理函数到控制器类
- 然后到控制器代码,检查执行方法
- 进入模型代码,以及服务代码
- 到数据库包代码
-
再到数据utility代码和其他utility代码,...
整个过程需要点时间,但会有效吗?当然管用的。尤其是应用的日志机制很好,我们会需要很少的时间来找到发生错误的代码位置。
这就足够了好了吗?有可能。但我猜,还有提升的空间。让我们开始,介绍实际很有帮助的快速小技巧。创建一个新的可导出函数Errorf(),将其放在utility包。在我的项目中,创建一个error-helper包来存放。
我们的Errorf()函数将替换fmt.Error()的功能,用于创建新的error对象函数。
之后,使用这个函数来取代fmt.Errorf()或errors.New()函数。当然也可能封装任何函数调用返回的错误。
思想就是用我们创建的Errorf()函数来封装每个错误对象。
这个函数做了两件事。其一,创建一个error对象和这点fmt.Error()相同。其二,错误将被记录。runtime.Caller(1)返回一些重要的信息例如文件名称和Errorf()函数被调用的代码行。这意味着,在错误发生的时候,我们可以看到详细的发生位置。(可能存在1-2行的偏差,根据错误被封装的具体情况而定)
如果我们尽可能地封装错误,我们最终能获取到详细的错误栈跟踪信息。
从上面的日志,可以清楚地看出特定错误发生的位置在crypto_helper.go:20。错误栈跟踪信息在auth_controller.go:83结束。非常清楚。
下面是实现的示例。很简单,仅封装error对象,即使是nil对象也没关系。
这个实现的另一个优点就是我们可以将实际正真错误原因传入,并且可扩展。如果你想将该实现和第三方错误追踪软件例如Sentry(链接)结合,只需要修改我们的Errorf()函数,仅此而起不需要做其他工作。