基于golang如何实现error工具包详解

前言

对于一门编程语言的开发者,类库包管理是一项考核编程语言成熟度的重要指标之一,Golang 也不例外。笔者在日常使用Golang语言开发系统程序时发现,在 Golang 的世界里,存在着大量的技术实现讨论和各种自制的解决方案。

最近在开发Go项目,发现Go语言本身存在的error并没有像触发panic时显示详细的调试信息。对于复杂的系统而言,这会让我们开发者需要一定的时间才能定位到错误。所以我们基本Go本身的error封装了一个可以快速定位错误工具包。下面让我们来看看这个工具包是怎么实现的。

设计思想

  • 工具包提供Err和Errf两个完善来登记错误,其用法分别类似于fmt.Print和fmt.Printf的使用方式,在参数的定义中添加了innerError参数来实现错误的传递,其值可为nil.
  • 对外提供StackTrace函数,方便使用者获取错误产生的堆栈信息。
  • 通过SetConfig方式实现对错误信息显示的配置,如在生产环境不需要打印堆栈信息。通过响应的配置即可关闭。

实现思路

工具包中主要是对堆栈信息的处理,就是如何才能定位到error的产生位置,通过查看官方文档,我们发现通过runtime包中的Callers和CallersFrames函数可以获取当前函数调用的堆栈信息。并且通过Skip参数和自定义过滤条件即可拿到error的产生位置。具体的实现过程如下:

对外提供的2个函数的实现

type Error struct {

err error

msg string

fullMsg string

stackTrace

}

func Errf(err error, format string, args ...interface{}) *Error {

e := &Error{

err: err,

msg: fmt.Sprintf(format, args),

}

e.fullMsg = e.genFullMsg()

return e

}

func Err(err error, args ...interface{}) *Error {

e := &Error{

err: err,

msg: fmt.Sprint(args),

}

e.fullMsg = e.genFullMsg()

return e

}

堆栈信息的实现

type stackTrace struct {

// stack info

data string

callers []uintptr

}

func (err *Error) getStackTrace() string {

if strings.TrimSpace(err.data) == "" {

return err.genStackTrace(5)

}

return err.data

}

func (err *Error) StackTrace() string {

return err.data

}

func (err *Error) genStackTrace(skip int) string {

if config.isPrintStack == 1 {

var buffer bytes.Buffer

buffer.WriteString("StackTrace:\n")

var st [64]uintptr

n := runtime.Callers(skip, st[:])

err.callers = st[:n]

frames := runtime.CallersFrames(err.callers)

for {

frame, ok := frames.Next()

if !ok {

break

}

if !strings.Contains(frame.File, "runtime/") {

buffer.WriteString(fmt.Sprintf("%s\n\t%s:%d\n",

frame.Func.Name(), frame.File, frame.Line))

}

}

err.data = buffer.String()

return err.data

}

return ""

}

错误信息显示配置的实现

const (

//print stack info

PRINTSTACK = 1

)

// global error config object

var config *errConfig = &errConfig{}

// error config

type errConfig struct {

isPrintStack uint32

}

//set error config info

func SetConfig(conf byte) {

if (conf & PRINTSTACK) != 0 {

atomic.CompareAndSwapUint32(&config.isPrintStack, 0, 1)

}

}

测试

func init() {

errors.SetConfig(errors.PRINTSTACK)

}

func main() {

a := func() {

err := errors.Err(nil, "this is an inner error")

fmt.Print(err.StackTrace())

b := errors.Errf(err, "this is a %s message", "test").Error()

fmt.Println(b)

}

a()

}

错误信息如下所示

 

结尾

该工具包只是对error信息和堆栈信息的封装,还存在含多不足的地方。如果各位有好的意见。欢迎指点。

总结:

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

以上是 基于golang如何实现error工具包详解 的全部内容, 来源链接: utcz.com/p/235257.html

回到顶部