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

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

  myfile.go: 14: Hello, world! 

If I end the log function this way, for example:

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

Each line emitted by this function will have a Printf call line number prefix. This is as expected, but the desired behavior for each line should be the prefix line number of the line where info is called.

Is there any way around this?

+7
callstack logging go
source share
2 answers

The log.Logger methods call Logger.Output() to send a message to the appropriate output. Logger.Output() allows you to pass calldepth (number of frames skipped).

Unfortunately, the log.Logger methods contain a wired-in calldepth , so you cannot provide an offset to skip the frame of the wrapper function.

But a much better alternative is to call this Logger.Output() from your wrapper, so you don't have to worry about frames and lines yourself. Also note that you do not need to add a new line "\n" , since the type log.Logger already does this if the message to be logged does not end with a new line.

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:

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

Exit (try on the Go Playground ):

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

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

+6
source share

I was about to include this in the question as my current workaround, but I believe this is the correct answer. I hope someone can tell me about the logger configuration parameter that I missed, which allows me to adjust the depth that the log uses when it calls runtime.Caller .

The 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("%v:%v: ", path.Base(file), line) if logger != nil { logger.Printf(prefix+format+"\n", args...) } } 
0
source share

All Articles