首發(fā): legendtkl.com
log的一個(gè)典型應(yīng)用場(chǎng)景就是實(shí)現(xiàn)log分級(jí)毙死,比如線上環(huán)境不需要記錄DEBUG的log信息。今天介紹一下glog。先看一個(gè)glog的簡(jiǎn)單例子塘砸。
//file name: glog.go
package main
import (
"flag"
"github.com/golang/glog"
)
func main() {
flag.Parse() // 1
glog.Info("This is a Info log") // 2
glog.Warning("This is a Warning log")
glog.Error("This is a Error log")
glog.V(1).Infoln("level 1") // 3
glog.V(2).Infoln("level 2")
glog.Flush() // 4
}
如果你之前沒(méi)有用過(guò)glog,需要使用go get
安裝一下晤锥,你需要像下面這樣執(zhí)行這個(gè)go程序掉蔬。上面標(biāo)注的幾個(gè)地方可以先注意一下,等文章讀完就理解了矾瘾。
$ go get
$ go build glog.go
$ ./glog -log_dir="./"
這時(shí)候不出意外的話女轿,會(huì)在同級(jí)目錄下生成下面幾個(gè)類似的log文件。
glog.kltao-mac.kltao.log.ERROR.20160312-173205.22052
glog.kltao-mac.kltao.log.INFO.20160312-173205.22052
glog.kltao-mac.kltao.log.WARNING.20160312-173205.22052
這就是產(chǎn)生的log文件壕翩,打開(kāi)第一個(gè)ERROR的log文件蛉迹,文件內(nèi)容如下。前面4行是文件響應(yīng)信息放妈,最后一行就是上面第14行代碼記錄的log內(nèi)容北救。
Log file created at: 2016/03/12 17:32:05
Running on machine: kltao-mac
Binary: Built with gc go1.4.2 for darwin/amd64
Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu threadid file:line] msg
E0312 17:32:05.568597 22052 glog.go:15] This is a Error log
這個(gè)時(shí)候如果你打開(kāi)另外兩個(gè)INFO和WARNING的log文件荐操,會(huì)發(fā)現(xiàn)WARNING日志文件中除了WARNING信息還記錄了Error信息(This is a Error log
),而INFO日志文件中則記錄了所有的log信息(This is a Info/Warning/Error log
)珍策。很容易理解托启,這些log是有等級(jí)的(ERROR>WARNING>INFO),高等級(jí)的日志內(nèi)容會(huì)同時(shí)會(huì)被記錄到低等級(jí)的日志文件中去膛壹。那么glog提供了一個(gè)等級(jí)呢驾中?答案是4個(gè),除了上面提出的3個(gè)模聋,還有一個(gè)FALTAL肩民。
這時(shí)候又有一個(gè)問(wèn)題來(lái)了,為什么第3處的日志信息沒(méi)有記錄下來(lái)呢链方?不急持痰,這個(gè)時(shí)候如下重新執(zhí)行一下。就可以在新的INFO日志文件中找到了對(duì)應(yīng)的信息了祟蚀。
./glog -log_dir="./" -v=3
對(duì)工窍,就是這個(gè)-v
參數(shù)。再說(shuō)V之前前酿,先說(shuō)一下glog的命令行解析患雏,對(duì)應(yīng)代碼就是標(biāo)注的第1處。那么glog有多少種參數(shù)呢罢维?
// By default, all log statements write to files in a temporary directory.
// This package provides several flags that modify this behavior.
// As a result, flag.Parse must be called before any logging is done.
//
// -logtostderr=false
// Logs are written to standard error instead of to files.
// -alsologtostderr=false
// Logs are written to standard error as well as to files.
// -stderrthreshold=ERROR
// Log events at or above this severity are logged to standard
// error as well as to files.
// -log_dir=""
// Log files will be written to this directory instead of the
// default temporary directory.
//
// Other flags provide aids to debugging.
//
// -log_backtrace_at=""
// When set to a file and line number holding a logging statement,
// such as
// -log_backtrace_at=gopherflakes.go:234
// a stack trace will be written to the Info log whenever execution
// hits that statement. (Unlike with -vmodule, the ".go" must be
// present.)
// -v=0
// Enable V-leveled logging at the specified level.
// -vmodule=""
// The syntax of the argument is a comma-separated list of pattern=N,
// where pattern is a literal file name (minus the ".go" suffix) or
// "glob" pattern and N is a V level. For instance,
// -vmodule=gopher*=3
// sets the V level to 3 in all Go files whose names begin "gopher".
glog.V(1).Infoln("level 1")
這行代碼表示設(shè)置的-v參數(shù)大于V()里面的參數(shù)才執(zhí)行后面的Infoln淹仑。如果不加-v參數(shù),默認(rèn)等級(jí)為0肺孵,所以第三處的代碼沒(méi)有執(zhí)行匀借。具體實(shí)現(xiàn)不妨看一下源碼實(shí)現(xiàn),一目了然平窘。
type Verbose bool
func V(level Level) Verbose {
// This function tries hard to be cheap unless there's work to do.
// The fast path is two atomic loads and compares.
// Here is a cheap but safe test to see if V logging is enabled globally.
if logging.verbosity.get() >= level {
return Verbose(true)
}
// It's off globally but it vmodule may still be set.
// Here is another cheap but safe test to see if vmodule is enabled.
if atomic.LoadInt32(&logging.filterLength) > 0 {
// Now we need a proper lock to use the logging structure. The pcs field
// is shared so we must lock before accessing it. This is fairly expensive,
// but if V logging is enabled we're slow anyway.
logging.mu.Lock()
defer logging.mu.Unlock()
if runtime.Callers(2, logging.pcs[:]) == 0 {
return Verbose(false)
}
v, ok := logging.vmap[logging.pcs[0]]
if !ok {
v = logging.setV(logging.pcs[0])
}
return Verbose(v >= level)
}
return Verbose(false)
}
func (v Verbose) Info(args ...interface{}) {
if v {
logging.print(infoLog, args...)
}
}
func (v Verbose) Infoln(args ...interface{}) {
if v {
logging.println(infoLog, args...)
}
}
func (v Verbose) Infof(format string, args ...interface{}) {
if v {
logging.printf(infoLog, format, args...)
}
}
程序中標(biāo)注的4個(gè)地方吓肋,除了第4個(gè)地方,其他都說(shuō)了瑰艘,F(xiàn)lush的作用清空緩沖區(qū)是鬼,就是把日志寫(xiě)到文件。golog初始化的時(shí)候磅叛,起了一個(gè)Flush的守護(hù)進(jìn)程屑咳,然后定期去執(zhí)行I/O操作,所以退出的時(shí)候需要顯示清除一下緩沖區(qū)弊琴。glog啟動(dòng)的初始化代碼如下兆龙。
func init() {
...
go logging.flushDaemon()
}
上面應(yīng)該是glog的大部分使用方法了,更詳細(xì)的信息可以參考github.com/golang/glog。