From bf7e2420b0c9fcc43892053106e7ec2294da8de0 Mon Sep 17 00:00:00 2001 From: Stephen Hitchner Date: Wed, 12 Oct 2016 11:04:11 -0700 Subject: [PATCH 1/3] making PC public so a stack trace can be accessed --- stack.go | 55 ++++++++++++++++++++++++++++++++++----------------- stack_test.go | 4 ++-- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/stack.go b/stack.go index 6b1f289..b2ab6e0 100644 --- a/stack.go +++ b/stack.go @@ -13,30 +13,49 @@ type Frame uintptr // pc returns the program counter for this frame; // multiple frames may have the same PC value. -func (f Frame) pc() uintptr { return uintptr(f) - 1 } +func (f Frame) PC() uintptr { return uintptr(f) - 1 } -// file returns the full path to the file that contains the -// function for this Frame's pc. -func (f Frame) file() string { - fn := runtime.FuncForPC(f.pc()) +// FunctionFileLine returns the function name, full path, and line number +// for the Frame's pc. +func (f Frame) FunctionFileLine() (string, string, int) { + fn := runtime.FuncForPC(f.PC()) if fn == nil { - return "unknown" + return "unknown", "unknown", 0 } - file, _ := fn.FileLine(f.pc()) + file, line := fn.FileLine(f.PC()) + return fn.Name(), file, line +} + +// File returns the full path to the file that contains the +// function for this Frame's pc. +func (f Frame) File() string { + _, file, _ := f.FunctionFileLine() return file } -// line returns the line number of source code of the +// Line returns the line number of source code of the // function for this Frame's pc. -func (f Frame) line() int { - fn := runtime.FuncForPC(f.pc()) - if fn == nil { - return 0 - } - _, line := fn.FileLine(f.pc()) +func (f Frame) Line() int { + _, _, line := f.FunctionFileLine() return line } +// Package returns the package name of the function of +// for this Frame's pc. +func (f Frame) Package() string { + name, _, _ := f.FunctionFileLine() + i := strings.Index(name, ".") + return name[:i] +} + +// Function returns the function name of the function of +// for this Frame's pc. +func (f Frame) Function() string { + name, _, _ := f.FunctionFileLine() + i := strings.Index(name, ".") + return name[i+1:] +} + // Format formats the frame according to the fmt.Formatter interface. // // %s source file @@ -53,7 +72,7 @@ func (f Frame) Format(s fmt.State, verb rune) { case 's': switch { case s.Flag('+'): - pc := f.pc() + pc := f.PC() fn := runtime.FuncForPC(pc) if fn == nil { io.WriteString(s, "unknown") @@ -62,12 +81,12 @@ func (f Frame) Format(s fmt.State, verb rune) { fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) } default: - io.WriteString(s, path.Base(f.file())) + io.WriteString(s, path.Base(f.File())) } case 'd': - fmt.Fprintf(s, "%d", f.line()) + fmt.Fprintf(s, "%d", f.Line()) case 'n': - name := runtime.FuncForPC(f.pc()).Name() + name := runtime.FuncForPC(f.PC()).Name() io.WriteString(s, funcname(name)) case 'v': f.Format(s, 's') diff --git a/stack_test.go b/stack_test.go index 510c27a..353ba79 100644 --- a/stack_test.go +++ b/stack_test.go @@ -33,7 +33,7 @@ func TestFrameLine(t *testing.T) { }} for _, tt := range tests { - got := tt.Frame.line() + got := tt.Frame.Line() want := tt.want if want != got { t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got) @@ -156,7 +156,7 @@ func TestTrimGOPATH(t *testing.T) { }} for i, tt := range tests { - pc := tt.Frame.pc() + pc := tt.Frame.PC() fn := runtime.FuncForPC(pc) file, _ := fn.FileLine(pc) got := trimGOPATH(fn.Name(), file) From 6860375ab2a6a29171cfc5c1f9b52e3e8df76478 Mon Sep 17 00:00:00 2001 From: Stephen Hitchner Date: Wed, 12 Oct 2016 13:56:03 -0700 Subject: [PATCH 2/3] adding tests --- stack_test.go | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/stack_test.go b/stack_test.go index 353ba79..124eab6 100644 --- a/stack_test.go +++ b/stack_test.go @@ -41,6 +41,72 @@ func TestFrameLine(t *testing.T) { } } +func TestFrameFuncation(t *testing.T) { + var tests = []struct { + Frame + want string + }{{ + Frame(initpc), + "", + }, { + func() Frame { + var pc, _, _, _ = runtime.Caller(0) + return Frame(pc) + }(), + "", + }, { + func() Frame { + var pc, _, _, _ = runtime.Caller(1) + return Frame(pc) + }(), + "", + }, { + Frame(0), // invalid PC + "", + }} + + for _, tt := range tests { + got := tt.Frame.Function() + want := tt.want + if want != got { + t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got) + } + } +} + +func TestFramePackage(t *testing.T) { + var tests = []struct { + Frame + want string + }{{ + Frame(initpc), + "", + }, { + func() Frame { + var pc, _, _, _ = runtime.Caller(0) + return Frame(pc) + }(), + "", + }, { + func() Frame { + var pc, _, _, _ = runtime.Caller(1) + return Frame(pc) + }(), + "", + }, { + Frame(0), // invalid PC + "", + }} + + for _, tt := range tests { + got := tt.Frame.Package() + want := tt.want + if want != got { + t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got) + } + } +} + type X struct{} func (x X) val() Frame { From 2b67a4a40be3fc79045db7bdaa7db58bd8e3b54d Mon Sep 17 00:00:00 2001 From: Stephen Hitchner Date: Wed, 12 Oct 2016 14:39:13 -0700 Subject: [PATCH 3/3] updating tests --- stack.go | 18 ++++++++++++++---- stack_test.go | 18 +++++++++--------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/stack.go b/stack.go index b2ab6e0..2205298 100644 --- a/stack.go +++ b/stack.go @@ -44,16 +44,26 @@ func (f Frame) Line() int { // for this Frame's pc. func (f Frame) Package() string { name, _, _ := f.FunctionFileLine() - i := strings.Index(name, ".") - return name[:i] + if i := strings.LastIndex(name, "/"); i != -1 { + name = name[i+1:] + if i := strings.Index(name, "."); i != -1 { + return name[:i] + } + } + return name } // Function returns the function name of the function of // for this Frame's pc. func (f Frame) Function() string { name, _, _ := f.FunctionFileLine() - i := strings.Index(name, ".") - return name[i+1:] + if i := strings.LastIndex(name, "/"); i != -1 { + name = name[i+1:] + if i := strings.Index(name, "."); i != -1 { + return name[i+1:] + } + } + return name } // Format formats the frame according to the fmt.Formatter interface. diff --git a/stack_test.go b/stack_test.go index 124eab6..07cb499 100644 --- a/stack_test.go +++ b/stack_test.go @@ -41,28 +41,28 @@ func TestFrameLine(t *testing.T) { } } -func TestFrameFuncation(t *testing.T) { +func TestFrameFunction(t *testing.T) { var tests = []struct { Frame want string }{{ Frame(initpc), - "", + "init", }, { func() Frame { var pc, _, _, _ = runtime.Caller(0) return Frame(pc) }(), - "", + "TestFrameFunction.func1", }, { func() Frame { var pc, _, _, _ = runtime.Caller(1) return Frame(pc) }(), - "", + "TestFrameFunction", }, { Frame(0), // invalid PC - "", + "unknown", }} for _, tt := range tests { @@ -80,22 +80,22 @@ func TestFramePackage(t *testing.T) { want string }{{ Frame(initpc), - "", + "errors", }, { func() Frame { var pc, _, _, _ = runtime.Caller(0) return Frame(pc) }(), - "", + "errors", }, { func() Frame { var pc, _, _, _ = runtime.Caller(1) return Frame(pc) }(), - "", + "errors", }, { Frame(0), // invalid PC - "", + "unknown", }} for _, tt := range tests {