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