Skip to content

Commit

Permalink
Merge pull request #1 from richdawe-cio/reinstate-pkg-errors-stacktrace
Browse files Browse the repository at this point in the history
Reinstate stacktraces for errors.WithStack from pkg/errors
  • Loading branch information
richdawe-cio authored Oct 11, 2024
2 parents 5c24d51 + 6f15ca4 commit 4b45308
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .mise.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tools]
go = "1.22.3"
28 changes: 26 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# raven

## This was forked from github.com/getsentry/raven-go

These links do not apply to this fork:

[![Build Status](https://api.travis-ci.org/getsentry/raven-go.svg?branch=master)](https://travis-ci.org/getsentry/raven-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/raven-go)](https://goreportcard.com/report/github.com/getsentry/raven-go)
[![GoDoc](https://godoc.org/github.com/getsentry/raven-go?status.svg)](https://godoc.org/github.com/getsentry/raven-go)
Expand All @@ -20,7 +24,27 @@ event/error logging system.
## Installation

```text
go get github.com/getsentry/raven-go
go get github.com/richdawe-cio/raven-go
```

Note: Go 1.7 and newer are supported.
Note: Go 1.22 and newer are supported. Earlier and newer versions may work, but have not been tested with this fork.

## Testing

```bash
go test .
```

Unfortunately this results in a few test failures. Since this fork has minimally changed, I do not consider these blockers for shipping the module. But they do need fixing. They are probably related to the switch to a modern go module.

```
--- FAIL: TestFunctionName (0.00s)
stacktrace_test.go:50: incorrect package; got github.com/richdawe-cio/raven-go, want .
--- FAIL: TestStacktraceFrame (0.00s)
stacktrace_test.go:84: incorrect Module: github.com/richdawe-cio/raven-go
stacktrace_test.go:87: incorrect Lineno: 18
stacktrace_test.go:90: expected InApp to be true
--- FAIL: TestStacktraceErrorsWithStack (0.00s)
stacktrace_test.go:141: incorrect Module: github.com/richdawe-cio/raven-go
stacktrace_test.go:150: incorrect Module: github.com/richdawe-cio/raven-go
```
9 changes: 5 additions & 4 deletions example/example.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package main
import (
"errors"
"fmt"
"github.com/getsentry/raven-go"
"log"
"net/http"
"os"

"github.com/richdawe-cio/raven-go"
)

func trace() *raven.Stacktrace {
Expand All @@ -31,9 +32,9 @@ func main() {

// CheckError sends error report to sentry and records event id and error name to the logs
func CheckError(err error, r *http.Request) {
client, err := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"})
if err != nil {
log.Fatal(err)
client, clientErr := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"})
if clientErr != nil {
log.Fatal(clientErr)
}
packet := raven.NewPacket(err.Error(), raven.NewException(err, trace()), raven.NewHttp(r))
eventID, _ := client.Capture(packet, nil)
Expand Down
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/richdawe-cio/raven-go

go 1.22

require (
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d
github.com/pkg/errors v0.9.1
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s=
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
56 changes: 51 additions & 5 deletions stacktrace.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"runtime"
"strings"
"sync"

"github.com/pkg/errors"
)

// Stacktrace defines Sentry's spec compliant interface holding Stacktrace information - https://docs.sentry.io/development/sdk-dev/interfaces/stacktrace/
Expand Down Expand Up @@ -52,8 +54,52 @@ type StacktraceFrame struct {
InApp bool `json:"in_app"`
}

func getPkgErrorsStacktrace(err error, context int, appPackagePrefixes []string) *Stacktrace {
type pkgErrorsStacktracer interface {
StackTrace() errors.StackTrace
}

stacktracer, errHasStacktrace := err.(pkgErrorsStacktracer)
if !errHasStacktrace {
return nil
}

st := stacktracer.StackTrace()
var frames []*StacktraceFrame

for _, f := range st {
pc := uintptr(f) - 1
// pc := uintptr(st[i]) - 1
// pc := uintptr(f)
fn := runtime.FuncForPC(pc)
// fmt.Fprintln(os.Stderr, pc, fn, st[i])
var fName string
var file string
var line int
if fn != nil {
file, line = fn.FileLine(pc)
fName = fn.Name()
} else {
file = "unknown"
fName = "unknown"
}
frame := NewStacktraceFrame(pc, fName, file, line, context, appPackagePrefixes)
if frame != nil {
frames = append([]*StacktraceFrame{frame}, frames...)
}
}

return &Stacktrace{Frames: frames}
}

// GetOrNewStacktrace tries to get stacktrace from err as an interface of github.com/pkg/errors, or else NewStacktrace()
func GetOrNewStacktrace(err error, skip int, context int, appPackagePrefixes []string) *Stacktrace {
// Try to extract stacktrace from errors.WithStack
pkgErrorsStacktrace := getPkgErrorsStacktrace(err, context, appPackagePrefixes)
if pkgErrorsStacktrace != nil {
return pkgErrorsStacktrace
}

type stackTracer interface {
StackTrace() []runtime.Frame
}
Expand Down Expand Up @@ -177,11 +223,11 @@ func isInAppFrame(frame StacktraceFrame, appPackagePrefixes []string) bool {
if frame.Module == "main" {
return true
}
for _, prefix := range appPackagePrefixes {
if strings.HasPrefix(frame.Module, prefix) && !strings.Contains(frame.Module, "vendor") && !strings.Contains(frame.Module, "third_party") {
return true
}
}
for _, prefix := range appPackagePrefixes {
if strings.HasPrefix(frame.Module, prefix) && !strings.Contains(frame.Module, "vendor") && !strings.Contains(frame.Module, "third_party") {
return true
}
}
return false
}

Expand Down
51 changes: 50 additions & 1 deletion stacktrace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"runtime"
"strings"
"testing"

"github.com/pkg/errors"
)

// a
Expand Down Expand Up @@ -55,7 +57,7 @@ func TestFunctionName(t *testing.T) {

func TestStacktrace(t *testing.T) {
st := trace()
if st == nil {
if st == nil || st.Frames == nil {
t.Error("got nil stacktrace")
}
if len(st.Frames) == 0 {
Expand Down Expand Up @@ -106,6 +108,53 @@ func TestStacktraceContext(t *testing.T) {
}
}

func traceErrorWithStack() error {
return errors.WithStack(errors.New("oops"))
}

func TestStacktraceErrorsWithStack(t *testing.T) {
err := traceErrorWithStack()
st := GetOrNewStacktrace(err, 0, 0, []string{thisPackage})

if st == nil || st.Frames == nil {
t.Error("failed to get stacktrace from errors.WithStack() error")
}
if len(st.Frames) != 3 {
t.Error("unexpected number of stack frames")
}
if st.Frames[0] == nil {
t.Error("frame 0 is nil")
}

// 0: tRunner
f := st.Frames[0]
if f.Function != "tRunner" {
t.Error("incorrect Function", f.Function)
}

// 1: TestStacktraceErrorsWithStack (this function)
f = st.Frames[1]
if f.Function != "TestStacktraceErrorsWithStack" {
t.Error("incorrect Function", f.Function)
}
if f.Module != thisPackage {
t.Error("incorrect Module:", f.Module)
}

// 2: traceErrorWithStack
f = st.Frames[2]
if f.Function != "traceErrorWithStack" {
t.Error("incorrect Function", f.Function)
}
if f.Module != thisPackage {
t.Error("incorrect Module:", f.Module)
}

// for i, frame := range st.Frames {
// fmt.Fprintf(os.Stderr, "[%d]: %+v\n", i, frame)
// }
}

func derivePackage() (file, pack string) {
// Get file name by seeking caller's file name.
_, callerFile, _, ok := runtime.Caller(1)
Expand Down

0 comments on commit 4b45308

Please sign in to comment.