go log 包


1   错误相关的概念

基于上面概念,我们可以把异常归为以下两种分类:

  1. 错误转恐慌,比如程序逻辑上尝试请求某个 URL,最多尝试三次,尝试三次的过程中请求失败是错误,尝试完第三次还不成功的话,失败就被提升为恐慌宕机了。
  2. 恐慌转错误,比如 panic 触发的异常被 recover 恢复后,将返回值中 error 类型的变量进行赋值,以便上层函数继续走错误处理流程。

基本上 goland 能提示的错误都是编译错误,此时如果进行编译,就会得到以下的错误信息 # github.com/wpxun/client
.\main.go:45:20: cannot convert nima (type xx) to type string 在 Goland IDE 中一般会对输出做区分:一般 stdout 用黑色字体,stderr 用红色字体

2   fmt 包

打印本质上就是把流写到 writer 对象上,并为了方便调用,提供了一系列函数。比如 Printf 并定制了 format 格式输出:

//打印结构体 var my myStruct = myStruct{1, map[int]string{1:“123”, 2:“345”}} fmt.Printf("%#v,%v", my, my)

## 3   log 包
log.Logger 结构体核心属性是三个:文件描识符、前缀和标签。默认初始化`var std = New(os.Stderr, "", LstdFlags)`,就是对三个属性的设置,可以看出默认是错误输出,并已经设置默认的 flags。包的使用方式主要有两种:
- 使用默认的 std 变量,用于测试
- 使用自定义的 log.Logger 变量,调用 log.New 初始化,运用于产品

log 公开的函数或 Logger 方法都是调用了 Logger.Output() 方法,有两个参数:
- calldepth:输出文件名的时候指向的函数栈的深度,仅在 Llongfile or Lshortfile 被设置时才起作用;0 层表示 Logger.Output() 处的 runtime.Caller(calldepth),1 层表示调用Output那一行,也就是当前行,2 层表示再往上一层,也就是调用输出的函数栈;一般都设置为指向当前调用行或其上一个栈,所以层层调用要算好栈的深度。
- 字符串,可以使用 fmt.Sprintf 进行格式化后再输入

## 4   经验总结

- 调用方具有更多关于正在运行的程序的上下文,并且可以做出关于如何处理错误的更明智的决定(比如错误发生3次才做处理),**所以谁调用,谁处理;这样的原则有很多,比如 molloc/free集中在同一个函数,谁发起 goroutine,谁就保证该 goroutine 不会泄漏,谁生成了 channel,谁就负责关闭 channel,channel 重复关闭会引发恐慌**。
- 一般以模块为边界设计 Error,不同边界(或者不同层)采用 wrap 的方式嵌套,将异常进行传递,直到传递到调用方进行处理,这样的好处是各层的异常信息都传递了,并且每一层还可以附加最明了的错误信息,这有两个好处:
  - 明了的信息,这个明了的信息对用户友好,一般是“直接上层”传递过来的异常的友好说明,而不会再追究“上层以上的层”的错误信息
  - 完整的错误链,因为嵌套的原因,所以可以把结构体输出却可
- 设计要异常传递的信息,不要等到最后才去优化,就如同“超时取消”的设计一样,应该在最开始的阶段就设计好
- 设计需要的信息:区分项目、区分日志类型,日志格式,用标准的语言描述:
  - 发生了什么
  - 发生在什么时间、什么位置
  - 对用户友好的信息
  - 告诉用户如何获得更多的信息