当我们需要打印日志的时候经常会需要标示当前的代码位置信息,包括所在文件名,行号,以及所在函数等等;特别是在处理log信息的时候。
go语言提供的runtime和reflect库可以帮助我们获取这些信息。下面是一个重写的log函数例子;自定义了一套log接口: ENTRY/EXIT/INFO/DEBUG等等,这些接口都是相似,所以代码例子只给出了ENTRY和DEBUG
package main
import (
"fmt"
"log"
"strings"
"runtime"
_"reflect"
"path/filepath"
)
type MyStruct struct {
}
func (m *MyStruct) foo(p string) {
ENTRY("")
ENTRY("Param p=%s", p)
DEBUG("Test %s %s", "Hello", "World")
}
func DEBUG(formating string, args... interface{}) {
LOG("DEBUG", formating, args...)
}
func ENTRY(formating string, args... interface{}) {
LOG("ENTRY", formating, args...)
}
func LOG(level string, formating string, args... interface{}) {
filename, line, funcname := "???", 0, "???"
pc, filename, line, ok := runtime.Caller(2)
// fmt.Println(reflect.TypeOf(pc), reflect.ValueOf(pc))
if ok {
funcname = runtime.FuncForPC(pc).Name() // main.(*MyStruct).foo
funcname = filepath.Ext(funcname) // .foo
funcname = strings.TrimPrefix(funcname, ".") // foo
filename = filepath.Base(filename) // /full/path/basename.go => basename.go
}
log.Printf("%s:%d:%s: %s: %s\n", filename, line, funcname, level, fmt.Sprintf(formating, args...))
}
func main() {
ss := MyStruct{}
ss.foo("helloworld")
}
编译运行
$ go build main.go && ./main
2017/09/24 09:37:29 main.go:17:foo: ENTRY:
2017/09/24 09:37:29 main.go:18:foo: ENTRY: Param p=helloworld
2017/09/24 09:37:29 main.go:19:foo: DEBUG: Test Hello World
这样在log里面可以清楚的看到输出ENTRY/DEBUG语句所在的代码信息,包括所在文件,行号,以及函数名。