Go日志-标准库log
作者:程序员CKeen
博客:http://ckeen.cn
长期坚持做有价值的事!积累沉淀,持续成长,升维思考!希望把编码作为长期兴趣爱好😄
在做项目开发时,我们可以使用Go语言标准库的log包,还可以使用开源的日志包,但更多的是基于优秀的开源日志包进行二次开发,来实现定制化的日志功能。Go生态中也有一些非常优秀的开源日志包,例如logrus、zap等。
1.标准库log包介绍
标准库的log包实现了一个简单的日志功能,log包提供了Print、Panic和Fatal三类函数用于日志输出。因为是标准库自带的,所以不需要我们下载安装,使用起来非常方便。Go的标准库大量使用了log包,例如:net/http、net/rpc等。
2.标准库log包使用
我们看一下log包提供的的类型和方法:
2.1 标准库log包函数
这里log包提供了包级别的默认的方法和*log. Logger类型的实例方法。一般直接通过控制台打印日志的时候,我们可以直接使用包提供方法
log.SetPrefix("[test]")
log.Print("log Print method test, now:" + time.Now().String())
log.Printf("log Printf method test ,now:%s\n", time.Now().String())
log.Println("log Println method test,now: " + time.Now().String())
运行后打印如下:
[test]2022/06/16 20:07:17 log Print method test, now:2022-06-16 20:07:17.7808 +0800 CST m=+0.001844439
[test]2022/06/16 20:07:17 log Printf method test ,now:2022-06-16 20:07:17.780987 +0800 CST m=+0.002030950
[test]2022/06/16 20:07:17 log Println method test,now: 2022-06-16 20:07:17.780999 +0800 CST m=+0.002043035
如果想将日志写入文件,使用log包的SetOutput方法,设置写入的文件的io.Writer即可,如下:
filehandle , err := os.OpenFile("log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return;
}
log.SetOutput(filehandle)
还可以提供log提供的flags来设置日志输出的一些格式,有如下几种日志属性可供选择:
- Ldate:当前时区的日期,格式是:2009/01/23。
- Ltime:当前时区的时间,格式是:01:23:23,精确到秒。
- Lmicroseconds:当前时区的时间,格式是:01:23:23.862600,精确到微妙。
- Llongfile:全文件名和行号。
- Lshortfile:当前文件名和行号,会覆盖Llongfile。
- LUTC:使用UTC而非本地时区。
- Lmsgprefix:将“前缀”从行的开头移至消息之前。
- LstdFlags:标准Logger的默认值(Ldate、Ltime)。
不同的属性通过|进行连接处理,如下:
log.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile)
设置该格式化,我们可以看到打印的时间包含微秒信息,文件是长路径格式:
[test]2022/06/16 20:25:06.953597 /Users/ckeen/Documents/code/gosource/go-awesome/go-samples/main.go:106: log Print method test, now:2022-06-16 20:25:06.95345 +0800 CST m=+0.002667800
[test]2022/06/16 20:25:06.953632 /Users/ckeen/Documents/code/gosource/go-awesome/go-samples/main.go:107: log Printf method test ,now:2022-06-16 20:25:06.953627 +0800 CST m=+0.002844076
[test]2022/06/16 20:25:06.953648 /Users/ckeen/Documents/code/gosource/go-awesome/go-samples/main.go:108: log Println method test,now: 2022-06-16 20:25:06.953638 +0800 CST m=+0.002855108
2.2 log.Logger实例使用
除了使用包默认提供的方法,我们还可以通过创建一个*log. Logger类型的log实例,通过该实例提供的方法来进行日志打印输出。log.Logger提供如下方法让我们创建Logger实例:
func New(out io.Writer, prefix string, flag int) *Logger {
return &Logger{out: out, prefix: prefix, flag: flag}
}
通过New方法创建Logger的实例后,我们就可以调用其方法进行日志输出,如下:
filehandle , err := os.OpenFile("log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
return
}
logger := log.New(filehandle, "[test]", log.Ldate | log.Lmicroseconds | log.Llongfile)
logger.Print("log Print method test, now:" + time.Now().String())
logger.Printf("log Printf method test ,now:%s\n", time.Now().String())
logger.Println("log Println method test,now: " + time.Now().String())
2.3 从源码分析log函数和log.Logger的关系
我们看一下log包的源码,就可以看到,其实log包的Print方法,最终也是先创建log.Logger实例,作为log的默认实例,再调用实例的Print方法。我们跟到log.Print方法,如下:
func Print(v ...interface{}) {
std.Output(2, fmt.Sprint(v...))
}
我们查找到std,发现它是log的全局变量std,std定义如下:
var std = New(os.Stderr, "", LstdFlags)
所以最终使用的都是log.Logger实例的方法。
log.Logger主要提供了Print、Panic、Fatal三种类型的函数来记录日志:
- Print:打印日志,例如:log.Print("call Print: line1")
- Panic:打印日志后执行panic(s),s为日志内容。
- Fatal:打印日志后执行os.Exit(1)。
Print、Panic、Fatal函数还提供Println、Printf、Panicln、Panicf、Fatalln、Fatalf来格式化打印日志。Print底层调用fmt.Sprint(v...)
,Println底层调用fmt.Sprintln(v...)
,Printf底层调用了fmt.Sprintf(format, v...)
。