1. log包
作为程序调试手段和运行记录,log是非常重要的,现在多数情况下并不是通过某个调试器来进行debug了,而是通过打log的方式观察和调试程序。
可以根据自己的需要实现log功能,Go语言本身也已经内置了log包,这里研究Go语言内置log包的使用方法。
如果习惯看go doc,可以查阅go doc 来快速查阅log包的信息。
1.1 屏显log
屏幕显示即输出log到标准输出设备。
package main
import (
"log"
)
func main() {
log.Println("log.Println")
}
---------------
2018/03/29 10:09:20 log.Println
可以看到,直接使用log包,通过log.Println就可以向标准输出打印log,带有日期时间和自定义字符串。可以使用的函数还有print和printf,参考fmt包中的print函数家族的使用方法。
函数 | 原型 |
---|---|
func Print(v …interface{}) | |
Println | func Println(v …interface{}) |
Printf | func Printf(format string, v …interface{}) |
Print和Println,其实用起来没有什么区别,连续用log.Print,也并不会输出到同一行,还是每调用一次,就产生新的一行log。
1.2 panic, fatal
log包还提供了两个异常情况的处理函数,panic家族和fatal家族:
函数 | 原型 |
---|---|
Panic | func Panic(v …interface{}) |
Panicln | func Panicln(v …interface{}) |
Panicf | func Panicf(format string, v …interface{}) |
Fatal | func Fatal(v …interface{}) |
Fatalln | func Fatalln(v …interface{}) |
Fatalf | func Fatalf(format string, v …interface{}) |
panic会打印指定的log字符转,然后抛出异常,显示调用栈。
package main
import (
"log"
)
func main() {
defer log.Println("log in defer")
log.Println("log.Println")
log.Panicln("log.Panicln")
}
---------------
2018/03/29 10:34:27 log.Println
2018/03/29 10:34:27 log.Panicln
2018/03/29 10:34:27 log in defer
panic: log.Panicln
goroutine 1 [running]:
log.Panicln(0xc42003ff50, 0x1, 0x1)
/home/docker/go192/go/src/log/log.go:340 +0xc0
main.main()
/home/docker/go/test/log/src/main.go:11 +0x11b
exit status 2
log包中的Panic和系统内置的panic是一样的,运行到log.Panic的时候,打印log信息,然后会继续逆序执行defer,如果存在多级调用,以此返回上级,执行defer,最终打印调用栈。
而Fatal与Panic不同,区别是不会执行defer,也没有调用栈,直接os.Exit(1)了:
package main
import (
"log"
)
func main() {
defer log.Println("log in defer")
log.Println("log.Println")
log.Fatalln("log.Fatalln")
}
---------------
2018/03/29 10:38:33 log.Println
2018/03/29 10:38:33 log.Fatalln
exit status 1
1.3 设置格式
上面的例子都是用默认的输出格式,每行的最开始显示日期时间,然后显示给定的log内容。
如果需要改变最开始显示的内容,是可以通过设定flag和前缀来完成的。
1.3.1 SetFlags
可以设定的flag包括:
标志 | 含义 |
---|---|
Ldate | 日期:2009/01/23 |
Ltime | 时间:01:23:23 |
Lmicroseconds | 微秒分辨率:01:23:23.123123(用于增强Ltime位) |
Llongfile | 文件全路径名+行号: /a/b/c/d.go:23 |
Lshortfile | 文件无路径名+行号:d.go:23(会覆盖掉Llongfile) |
LstdFlags | 等于Ldate | Ltime,标准logger的初始值 |
通过例子看下各个flag的意义:
package main
import (
"log"
)
func main() {
log.SetFlags(log.Ldate)
log.Println("日期")
log.SetFlags(log.Ltime)
log.Println("时间")
log.SetFlags(log.Lmicroseconds)
log.Println("微秒")
log.SetFlags(log.Llongfile)
log.Println("全文件路径和行号")
log.SetFlags(log.Lshortfile)
log.Println("文件名和行号")
log.SetFlags(log.LstdFlags)
log.Println("标准")
log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile)
log.Println("组合: 日期 + 微秒 + 文件名和行号")
}
---------------
2018/03/29 日期
10:54:10 时间
10:54:10.582154 微秒
/home/docker/go/test/log/src/main.go:18: 全文件路径和行号
main.go:21: 文件名和行号
2018/03/29 10:54:10 标准
2018/03/29 10:54:10.582187 main.go:27: 组合: 日期 + 微秒 + 文件名和行号
1.3.2 SetPrefix
上一节设置的flag控制的是最前边显示的时间日期,文件名行号什么的。还可以通过SetPrefix来改变每一行最开始显示的字符串:
package main
import (
"log"
)
func main() {
log.SetPrefix("func main")
log.Println("含前缀")
}
---------------
func main:2018/03/29 10:59:36 含前缀
通过SetFlags和SetPrefix,对log格式的控制,基本可以满足绝大部分的log打印需要了。
1.4 log文件
输出log到文件,可以通过new一些logger,通过logger实例自己的方法调用,去写入不到不同的目标位置。
Logger方法 | 原型 |
---|---|
New | func New(out io.Writer, prefix string, flag int) *Logger |
Print家族 | 同log |
Panic家族 | 同log |
Fatal家族 | 同log |
SetFlags | 同log |
SetPrefix | 同log |
Output | func (l *Logger) Output(calldepth int, s string) error |
一个最简单的例子:
package main
import (
"log"
"os"
)
func main() {
dbgLog, err := os.OpenFile("./dbgLog.log", os.O_CREATE | os.O_APPEND| os.O_WRONLY, os.ModePerm)
if err != nil {
log.Fatalln("dbgLog.log创建失败")
}
errLog, err := os.OpenFile("./errLog.log", os.O_CREATE | os.O_APPEND| os.O_WRONLY, os.ModePerm)
if err != nil {
log.Fatalln("errLog.log创建失败")
}
dbgLogger := log.New(dbgLog, "[DEBUG] ", log.LstdFlags)
errLogger := log.New(errLog, "[ERROR] ", log.LstdFlags|log.Lshortfile)
log.Println("log文件创建成功")
dbgLogger.Println("调试信息log")
errLogger.Println("错误信息log")
}
---------------
2018/03/29 11:15:22 log文件创建成功
---------------
dbgLog.log
[DEBUG] 2018/03/29 11:15:22 调试信息log
---------------
errLog.log
[ERROR] 2018/03/29 11:15:22 main.go:24: 错误信息log
logger不仅可以在New的时候指定Flag,也可以通过与log相同的函数 SetFlags控制log格式,可以通过SetPrefix改变前缀。
对于常规log打印需求,log包已经可以完全满足需要了。