github.com/golang/glog. Golang glog使用详解

glog只提供了少数几个选项,通过命令行控制,例如:

-log_dir: 日志文件保存目录
-alsologtostderr: 日志写入文件的同时,输出到stderr
-v:配置V输出的等级。

glog使用非常简单,只需要import就可以了。glog package的init函数会初始化并启动一个glog 的flushDaemon协程,你只需要使用glog.Info, glog.Warning, glog.Error或glog.Fatal即可。

package main

import (
	"flag"
	"github.com/golang/glog"
)

func main() {
	flag.Parse()

	glog.Info("hello,glog")
	glog.Warning("Warning glog")
	glog.Error("error glog")

	glog.Infof("info %d",1)
	glog.Warningf("warning %d",2)
	glog.Errorf("error %d",3)

	glog.V(3).Infoln("info with v 3")
	glog.V(2).Infoln("info with v 2")
	glog.V(1).Infoln("info with v 1")
	glog.V(0).Infoln("info with v 0")

	// 退出时调用,确保日志写入文件中
	glog.Flush()
}

执行后:

 go run main.go -log_dir=log -alsologtostderr 

输出,同时会在log文件夹下生成日志文件:
在这里插入图片描述
有几点说明:
1、高等级的日志会同时输出到比它等级低的文件中,例如error日志会同时输出到error文件,warning文件,info文件中,依次类推;

2、启动时,调用flag.Parse用来初始化glog的参数,例如xxx.exe -log_dir=”./” -v=3。如果不提供参数,log_dir目录为
os.TempDir(),v的值为0

3、程序退出时,需要调用glog.Flush(),将日志写入文件中。

4、V函数。默认的v选项为0,可以通过命令行设置v值。V函数的功能是,当V函数的参数高于glog的v值时,不会执行后续的Info函数,否则就执行。

glog.V(2).Info
相当于
if glog.V(2) {
Info()
}
5、日志文件名

日志文件名由以下几部分组成:
程序名.电脑名.用户名.log.xxx.YYYYMMDD-HHMMSS.pid,其中

xxx为日志等级,例如INFO,ERROR,WARNING

YYYYMMDD为年月日

HHMMSS为小时,分钟,秒

pid是进程id

6、glog.Fatal的默认行为是输出Fatal等级日志,并强制进程退出,不过可以自定义Fatal的行为

glog 的使用与特性

glog 将日志级别分为 4 种,分别是:

INFO:普通日志;
WARNING:告警日志;
ERROR:错误日志;
FATAL:严重错误日志,打印完日志后程序将会推出(os.Exit()

glog 的使用很简单,可参考下面这个例子:

package main

import (
	"flag"
	"github.com/golang/glog"
)

func main() {
	flag.Parse()
	defer glog.Flush()

	glog.Info("This is info message")
	glog.Infof("This is info message:%v",12345)
	glog.InfoDepth(1,"This is info message",12345)

	glog.Warning("This is warning message")
	glog.Warningf("This is warning message:%v",12345)
	glog.WarningDepth(1,"This is warning message",12345)

	glog.Error("This is error message")
	glog.Errorf("This is error message:%v",12345)
	glog.ErrorDepth(1,"This is error message",12345)

	glog.Fatal("This is fatal message")
	glog.Fatalf("This is fatal message:%v",12345)
	glog.FatalDepth(1,"This is fatal message",12345)
}

当我们运行:

mkdir -p log && go run main.go -log_dir=log -alsologtostderr

以上打印日志将会同时打印在 log/ 目录和标准错误输出中(-alsologtostderr)。

其中在 log/ 中将会产生如下日志文件:
在这里插入图片描述
其中 main.INFO 这类文件表示的是 INFO 日志对应的符号链接。当单个日志文件达到一定大小时,glog 将会有 rotate 的动作:即关闭已经满量的文件,新建日志文件。

glog 最常用的就是 V level 的功能,如下所示:

package main

import (
	"flag"
	"github.com/golang/glog"
)

func main() {
	flag.Parse()
	defer glog.Flush()

	glog.V(3).Info("LEVEL 3 message")
	glog.V(4).Info("LEVEL 4 message")
	glog.V(5).Info("LEVEL 5 message")
	glog.V(6).Info("LEVEL 6 message")
}

当我们重新运行:

$ go run main.go -log_dir=log -alsologtostderr

在这里插入图片描述

将不会看到任何输出,因为日志级别不够,我们通过指定日志级别(-v,log level):

$ go run main.go -v=4 -log_dir=log -alsologtostderr

此时,日志级别小于或等于 4 的日志将被打印出来,在log文件夹下会新增一个日志文件,里面显示下面的信息:
在这里插入图片描述

vmodule 功能

如果我们想对不同的文件实行不同的日志级别,可以用 vmodule 功能,如下代码:
在这里插入图片描述
main.go

package main

import (
	"flag"
	"github.com/golang/glog"
)

func main() {
	flag.Parse()
	defer glog.Flush()

	bar()
	glog.V(3).Info("LEVEL 3 message")
	glog.V(4).Info("LEVEL 4 message")
	glog.V(5).Info("LEVEL 5 message")
	glog.V(8).Info("LEVEL 8 message")
}

bar.go

package main

import "github.com/golang/glog"

func bar() {
	glog.V(3).Info("LEVEL 3: level 3 message in bar.go")
	glog.V(4).Info("LEVEL 4: level 4 message in bar.go")
	glog.V(5).Info("LEVEL 5: level 5 message in bar.go")
	glog.V(6).Info("LEVEL 6: level 6 message in bar.go")
}

当我们执行:

$ go run main.go bar.go -v=4 -log_dir=log -alsologtostderr -vmodule=bar=5

对所有文件的日志级别设定为 4 (-v=4),但是对 bar.go (-vmodule 的输入参数省去 .go 后缀,且必须以 -vmodule=recordio=2,file=1,gfs*=3 的语法格式)的日志级别设定为 5,此时会输出:
在这里插入图片描述

通过该功能,可以对指定模块采用不同日志级别的输出,可有效提升调试效率。

traceLocation 功能

traceLocation 的命令格式为 -log_backtrace_at=gopherflakes.go:234,当运行到指定代码处时,将把该代码的栈信息打印出来,延续上面的代码,我们运行:

$ go run main.go bar.go -v=3 -log_dir=log -alsologtostderr -vmodule=bar=5 -log_backtrace_at=bar.go:6

可见如下输出,同时会在log文件夹下生成新的日志文件,记录日志内容:

I0911 17:54:52.281403    2667 bar.go:6] LEVEL 4: level 4 message in bar.go
goroutine 1 [running]:
github.com/golang/glog.stacks(0x11bec00, 0x11a44e2, 0x6, 0x6)
        /Users/quanying.yang/go/pkg/mod/github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b/glog.go:769 +0xb8
github.com/golang/glog.(*loggingT).output(0x11beba0, 0xc000000000, 0xc00010c000, 0x11a44e2, 0x6, 0x6, 0x0)
        /Users/quanying.yang/go/pkg/mod/github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b/glog.go:675 +0x6a1
github.com/golang/glog.(*loggingT).printDepth(0x11beba0, 0xc000000000, 0x1, 0xc000113ed8, 0x1, 0x1)
        /Users/quanying.yang/go/pkg/mod/github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b/glog.go:646 +0x129
github.com/golang/glog.(*loggingT).print(...)
        /Users/quanying.yang/go/pkg/mod/github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b/glog.go:637
github.com/golang/glog.Verbose.Info(...)
        /Users/quanying.yang/go/pkg/mod/github.com/golang/glog@v0.0.0-20160126235308-23def4e6c14b/glog.go:1032
main.bar()
        /Users/quanying.yang/go/src/awesomeProject1/demo2/bar.go:6 +0x9b
main.main()
        /Users/quanying.yang/go/src/awesomeProject1/demo2/main.go:12 +0xae
I0911 17:54:52.281869    2667 main.go:13] LEVEL 3 message

日志格式

从上面的例子可以看出,glog 打印的日志基本格式为:

<header>] <message>

I0911 17:54:52.281869    2667 main.go:13] LEVEL 3 message

header 和 message 之间用 ] 分隔。其中 header 的格式为:

Lmmdd hh:mm:ss.uuuuuu threadid file:line

这里要注意的是 L,它代表了 glog 原本的日志级别:

I -> INFO
W -> WARNING
E -> ERROR
F -> FATAL

后面几个字段分别代表的是时间信息。在 C++ 中,threadid 表示的是线程信息,但在 Go 版本实现中,threadid 是进程 PID,即 os.Getpid() 的调用结果。

这部分详细代码可参考:glog.go 中的 formatHeader() 函数。

glog 的实现

其实,用 Go 实现一个日志库并不困难,其本质就是:在 buffer 中写入格式化的内容并定期刷入文件中。glog 的基本实现逻辑也是如此。


版权声明:本文为ayqy42602原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。