【问题标题】:Is it possible to wrap log.Logger functions without losing the line number prefix?是否可以在不丢失行号前缀的情况下包装 log.Logger 函数?
【发布时间】:2017-08-03 09:30:02
【问题描述】:

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

myfile.go:14:你好,世界!

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

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

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

有什么办法吗?

【问题讨论】:

    标签: logging go callstack


    【解决方案1】:

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

    【讨论】:

    • 这就是我所说的:D 很好的答案
    【解决方案2】:

    我打算将此作为我当前的解决方法包含在问题中,但我认为这是一个有效的答案。我希望有人能告诉我一个我错过的记录器配置选项,它可以让我调整记录器在调用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...)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-20
      相关资源
      最近更新 更多