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

huangapple go评论84阅读模式
英文:

Is it possible to wrap log.Logger functions without losing the line number prefix?

问题

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

<pre>myfile.go:14: Hello, world!</pre>

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

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

这个函数发出的每一行都会以Printf调用的行号作为前缀。这是预期的行为,但期望的行为是每一行都以调用info的行号作为前缀。

有没有什么办法可以解决这个问题?

英文:

When using the log.Lshortfile flag, the logger prefixes all log lines with the file name and line number of the logger function call, for example:

<pre>myfile.go:14: Hello, world!</pre>

If I wrap the log function like this, for instance:

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

Every line emitted by this function is going to be prefixed with the line number of the Printf call. That is as expected, but the desired behavior is for each line to be prefixed with the line number of the line where info is called.

Is there any way around it?

答案1

得分: 17

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)。

英文:

Methods of log.Logger call the Logger.Output() method to send the message to the appropriate output. Logger.Output() allows you to pass the calldepth (the number of frames to skip).

Unfortunately methods of log.Logger contain the calldepth "wired in", so you can't provide an offset to skip the wrapper function's frame.

But a much better alternative is to call this Logger.Output() from your wrapper, so you don't have to bother with frames and lines yourself. Also note that you don't need to append a newline &quot;\n&quot;, as the log.Logger type already does that if the message to be logged does not end with a newline.

So a better and shorter alternative:

var myLogger = log.New(os.Stdout, &quot;[my]&quot;, log.Lshortfile)

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

Testing it:

func main() {
	log.SetFlags(log.Lshortfile)
	log.Println(&quot;hello&quot;)
	info(&quot;world&quot;)
}

Output (try it on the Go Playground):

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

As you can see, info() prints the proper line number (+1 compared to the line number printed by log.Println() in the previous line).

答案2

得分: 0

我本来打算将这个作为我的当前解决方法包含在问题中,但我想这也是一个有效的答案。我希望有人告诉我一个我可能错过的记录器配置选项,让我可以调整记录器在调用runtime.Caller时使用的深度。

一个解决方法是移除log.Lshortfile标志,并手动实现这个行为:

func info(format string, args ...interface{}) {
    _, file, line, _ := runtime.Caller(1)

    prefix := fmt.Sprintf("%v:%v: ", path.Base(file), line)

    if logger != nil {
        logger.Printf(prefix+format+"\n", args...)
    }
}
英文:

I was going to include this in the question as my current workaround, but I suppose it is a valid answer. I'm hoping somebody can tell me of a logger config option I've missed that lets me adjust the depth the logger uses when it calls runtime.Caller.

A workaround is to remove the log.Lshortfile flag and implement the behavior manually:

func info(format string, args ...interface{}) {
	_, file, line, _ := runtime.Caller(1)

	prefix := fmt.Sprintf(&quot;%v:%v: &quot;, path.Base(file), line)

	if logger != nil {
		logger.Printf(prefix+format+&quot;\n&quot;, args...)
	}
}

huangapple
  • 本文由 发表于 2017年3月13日 19:21:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/42762391.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定