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:
Michael Crosby 2014-10-22 23:10:51 +00:00 committed by Victor Marmol
parent 6310a958e6
commit 7760faaab4
5 changed files with 112 additions and 0 deletions

25
stacktrace/capture.go Normal file
View File

@ -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,
}
}

View File

@ -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)
}
}

35
stacktrace/frame.go Normal file
View 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
}

20
stacktrace/frame_test.go Normal file
View File

@ -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)
}
}

5
stacktrace/stacktrace.go Normal file
View File

@ -0,0 +1,5 @@
package stacktrace
type Stacktrace struct {
Frames []Frame
}