Add stacktrace package for collection of stacktraces
This helps aid our effort of returning useful errors. Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
6310a958e6
commit
7760faaab4
|
@ -0,0 +1,25 @@
|
|||
package stacktrace
|
||||
|
||||
import "runtime"
|
||||
|
||||
// Caputure captures a stacktrace for the current calling go program
|
||||
//
|
||||
// skip is the number of frames to skip
|
||||
func Capture(userSkip int) Stacktrace {
|
||||
var (
|
||||
skip = userSkip + 1 // add one for our own function
|
||||
frames []Frame
|
||||
)
|
||||
|
||||
for i := skip; ; i++ {
|
||||
pc, file, line, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
frames = append(frames, NewFrame(pc, file, line))
|
||||
}
|
||||
|
||||
return Stacktrace{
|
||||
Frames: frames,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package stacktrace
|
||||
|
||||
import "testing"
|
||||
|
||||
func captureFunc() Stacktrace {
|
||||
return Capture(0)
|
||||
}
|
||||
|
||||
func TestCaptureTestFunc(t *testing.T) {
|
||||
stack := captureFunc()
|
||||
|
||||
if len(stack.Frames) == 0 {
|
||||
t.Fatal("expected stack frames to be returned")
|
||||
}
|
||||
|
||||
// the first frame is the caller
|
||||
frame := stack.Frames[0]
|
||||
if expected := "captureFunc"; frame.Function != expected {
|
||||
t.Fatalf("expteced function %q but recevied %q", expected, frame.Function)
|
||||
}
|
||||
if expected := "github.com/docker/libcontainer/stacktrace"; frame.Package != expected {
|
||||
t.Fatalf("expected package %q but received %q", expected, frame.Package)
|
||||
}
|
||||
if expected := "capture_test.go"; frame.File != expected {
|
||||
t.Fatalf("expected file %q but received %q", expected, frame.File)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package stacktrace
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewFrame returns a new stack frame for the provided information
|
||||
func NewFrame(pc uintptr, file string, line int) Frame {
|
||||
fn := runtime.FuncForPC(pc)
|
||||
pack, name := parseFunctionName(fn.Name())
|
||||
return Frame{
|
||||
Line: line,
|
||||
File: filepath.Base(file),
|
||||
Package: pack,
|
||||
Function: name,
|
||||
}
|
||||
}
|
||||
|
||||
func parseFunctionName(name string) (string, string) {
|
||||
i := strings.LastIndex(name, ".")
|
||||
if i == -1 {
|
||||
return "", name
|
||||
}
|
||||
return name[:i], name[i+1:]
|
||||
}
|
||||
|
||||
// Frame contains all the information for a stack frame within a go program
|
||||
type Frame struct {
|
||||
File string
|
||||
Function string
|
||||
Package string
|
||||
Line int
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package stacktrace
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestParsePackageName(t *testing.T) {
|
||||
var (
|
||||
name = "github.com/docker/libcontainer/stacktrace.captureFunc"
|
||||
expectedPackage = "github.com/docker/libcontainer/stacktrace"
|
||||
expectedFunction = "captureFunc"
|
||||
)
|
||||
|
||||
pack, funcName := parseFunctionName(name)
|
||||
if pack != expectedPackage {
|
||||
t.Fatalf("expected package %q but received %q", expectedPackage, pack)
|
||||
}
|
||||
|
||||
if funcName != expectedFunction {
|
||||
t.Fatalf("expected function %q but received %q", expectedFunction, funcName)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package stacktrace
|
||||
|
||||
type Stacktrace struct {
|
||||
Frames []Frame
|
||||
}
|
Loading…
Reference in New Issue