7

Given the following code (copied from here):

     1  package main
     2  
     3  import (
     4      "fmt"
     5  
     6      "github.com/pkg/errors"
     7  
     8      "go.uber.org/zap"
     9  )
    10  
    11  func main() {
    12      logger, _ := zap.NewProduction()
    13      defer logger.Sync()
    14  
    15      sugar := logger.Sugar()
    16      result, err := caller1()
    17      if err != nil {
    18          sugar.Error(err)
    19          return
    20      }
    21      fmt.Println("Result: ", result)
    22  }
    23  
    24  func caller1() (int, error) {
    25      err := caller2()
    26      if err != nil {
    27          return 0, err
    28      }
    29      return 1, nil
    30  }
    31  
    32  func caller2() error {
    33      doSomething()
    34      return caller3()
    35  }
    36  
    37  func caller3() error {
    38      return errors.New("failed")
    39  }
    40  
    41  func doSomething() {}

Since we are using github.com/pkg/errors package, I know that to log the stack trace, just use sugar.Errorf("%+v", err):

$ go run stacktrace.go 2>&1 | jq
{
  "level": "error",
  "ts": 1606501191.539652,
  "caller": "zap/stacktrace.go:18",
  "msg": "failed\nmain.caller3\n\t/Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:38\nmain.caller2\n\t/Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:34\nmain.caller1\n\t/Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:25\nmain.main\n\t/Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:16\nruntime.main\n\t/usr/local/Cellar/go/1.15.2/libexec/src/runtime/proc.go:204\nruntime.goexit\n\t/usr/local/Cellar/go/1.15.2/libexec/src/runtime/asm_amd64.s:1374",
  "stacktrace": "main.main\n\t/Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:18\nruntime.main\n\t/usr/local/Cellar/go/1.15.2/libexec/src/runtime/proc.go:204"
}

The thing is the stack trace is put under the msg key and the one under the stacktrace is the stack trace of the logging line:

main.main
    /Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:18
runtime.main
    /usr/local/Cellar/go/1.15.2/libexec/src/runtime/proc.go:204

not the stack trace of the error:

main.caller3
    /Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:38
main.caller2
    /Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:34
main.caller1
    /Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:25
main.main
    /Users/quanta/go/src/github.com/quantonganh/zap/stacktrace.go:16
runtime.main
    /usr/local/Cellar/go/1.15.2/libexec/src/runtime/proc.go:204
runtime.goexit
    /usr/local/Cellar/go/1.15.2/libexec/src/runtime/asm_amd64.s:1374

Question: how can I log the "real" stack trace under the stacktrace key?

blackgreen
  • 34,072
  • 23
  • 111
  • 129
quanta
  • 3,960
  • 4
  • 40
  • 75

1 Answers1

6

I have looked into the source code and I think we cannot do that.

Log messages are formatted and put under the msg key.

The stack trace is taken from runtime.CallersFrames at the time of logging.

The reason I asked this question is before using %+v to get the complete call stack, I just looked at the "stacktrace" value and wondering:

  • Why it is missing?
  • Why it just point to the logging line instead of pointing to the actual error?
quanta
  • 3,960
  • 4
  • 40
  • 75