Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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:

myfile.go:14: Hello, world!

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

func info(pattern string, args ...interface{}) {
    myLogger.Printf(pattern + "\n", 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?

like image 476
Hubro Avatar asked Mar 13 '17 11:03

Hubro


1 Answers

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 "\n", 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, "[my]", 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("hello")
    info("world")
}

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

like image 73
icza Avatar answered Nov 15 '22 18:11

icza