是否可以在不丢失行号前缀的情况下包装log.Logger函数?

时间:2017-03-13 11:21:16

标签: logging go callstack

使用log.Lshortfile标志时,记录器会在所有日志行前加上记录器函数调用的文件名和行号,例如:

myfile.go:14: Hello, world!

如果我像这样包装日志函数,例如:

func info(pattern string, args ...interface{}) {
    myLogger.Printf(pattern + "\n", args...)
}

此函数发出的每一行都将以Printf调用的行号为前缀。这是预期的,但所需的行为是每行以前缀为info的行的行号为前缀。

周围有什么办法吗?

2 个答案:

答案 0 :(得分:8)

log.Logger方法调用Logger.Output()方法将消息发送到适当的输出。 Logger.Output()允许您传递calldepth(要跳过的帧数)。

不幸的是log.Logger的方法包含calldepth“有线”,因此您无法提供偏移量来跳过包装函数的帧。

但更好的选择是从你的包装器中调用这个Logger.Output(),这样你就不必费心去处理框架和线条了。另请注意,您不需要附加换行符"\n",因为如果要记录的邮件不以换行符结尾,log.Logger类型已经这样做了。

这是一个更好,更短的选择:

var myLogger = log.New(os.Stdout, "[my]", log.Lshortfile)

func info(pattern string, args ...interface{}) {
    myLogger.Output(2, fmt.Sprintf(pattern, args...))
}

测试它:

func main() {
    log.SetFlags(log.Lshortfile)
    log.Println("hello")
    info("world")
}

输出(在Go Playground上尝试):

main.go:11: hello
[my]main.go:12: world

如您所见,info()会打印正确的行号(与前一行中log.Println()打印的行号相比+1)。

答案 1 :(得分:0)

我打算将此问题作为我当前的解决方法,但我认为这是一个有效的答案。我希望有人能告诉我一个记录器配置选项我错过了让我调整记录器调用 foreach ($arr as $newarray ) { if (is_array($newarray)) print_r( array_filter($newarray) ); } 时使用的深度。

解决方法是删除runtime.Caller标志并手动实现该行为:

log.Lshortfile