Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleans up the stack trace, #138

Merged
merged 3 commits into from
Jan 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion actor/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func TestRestarts(t *testing.T) {
if msg.data != 10 {
panic("I failed to process this message")
} else {
fmt.Println("finally processed all my messsages after borking.", msg.data)
fmt.Println("finally processed all my messages after borking", msg.data)
wg.Done()
}
}
Expand Down
26 changes: 24 additions & 2 deletions actor/process.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package actor

import (
"bytes"
"fmt"
"github.com/DataDog/gostackparse"
"log/slog"
"runtime/debug"
"sync"
Expand Down Expand Up @@ -149,8 +151,7 @@ func (p *process) tryRestart(v any) {
p.Start()
return
}
stackTrace := debug.Stack()
fmt.Println(string(stackTrace))
stackTrace := cleanTrace(debug.Stack())
// If we reach the max restarts, we shutdown the inbox and clean
// everything up.
if p.restarts == p.MaxRestarts {
Expand Down Expand Up @@ -210,3 +211,24 @@ func (p *process) Send(_ *PID, msg any, sender *PID) {
p.inbox.Send(Envelope{Msg: msg, Sender: sender})
}
func (p *process) Shutdown(wg *sync.WaitGroup) { p.cleanup(wg) }

func cleanTrace(stack []byte) []byte {
goros, err := gostackparse.Parse(bytes.NewReader(stack))
if err != nil {
slog.Error("failed to parse stacktrace", "err", err)
return stack
}
if len(goros) != 1 {
slog.Error("expected only one goroutine", "goroutines", len(goros))
return stack
}
// skip the first frames:
goros[0].Stack = goros[0].Stack[4:]
buf := bytes.NewBuffer(nil)
_, _ = fmt.Fprintf(buf, "goroutine %d [%s]\n", goros[0].ID, goros[0].State)
for _, frame := range goros[0].Stack {
_, _ = fmt.Fprintf(buf, "%s\n", frame.Func)
_, _ = fmt.Fprint(buf, "\t", frame.File, ":", frame.Line, "\n")
}
return buf.Bytes()
}
49 changes: 49 additions & 0 deletions actor/process_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package actor

import (
"bytes"
"fmt"
"github.com/stretchr/testify/require"
"testing"
"time"
)

// Test_CleanTrace tests that the stack trace is cleaned up correctly and that the function
// which triggers the panic is at the top of the stack trace.
func Test_CleanTrace(t *testing.T) {
e, err := NewEngine(nil)
require.NoError(t, err)
type triggerPanic struct {
data int
}
stopCh := make(chan struct{})
pid := e.SpawnFunc(func(c *Context) {
fmt.Printf("Got message type %T\n", c.Message())
switch c.Message().(type) {
case Started:
c.Engine().Subscribe(c.pid)
case triggerPanic:
panicWrapper()
case ActorRestartedEvent:
m := c.Message().(ActorRestartedEvent)
// split the panic into lines:
lines := bytes.Split(m.Stacktrace, []byte("\n"))
// check that the second line is the panicWrapper function:
if bytes.Contains(lines[1], []byte("panicWrapper")) {
fmt.Println("stack trace contains panicWrapper at the right line")
stopCh <- struct{}{}
}
}
}, "foo", WithMaxRestarts(1))
e.Send(pid, triggerPanic{1})
select {
case <-stopCh:
fmt.Println("test passed")
case <-time.After(time.Second):
t.Error("test timed out. stack trace likely did not contain panicWrapper at the right line")
}
}

func panicWrapper() {
panic("foo")
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/anthdm/hollywood
go 1.21

require (
github.com/DataDog/gostackparse v0.7.0
github.com/grandcat/zeroconf v1.0.0
github.com/planetscale/vtprotobuf v0.4.0
github.com/prometheus/client_golang v1.15.0
Expand Down
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/DataDog/gostackparse v0.7.0 h1:i7dLkXHvYzHV308hnkvVGDL3BR4FWl7IsXNPz/IGQh4=
github.com/DataDog/gostackparse v0.7.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao=
Expand Down Expand Up @@ -57,6 +59,7 @@ github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/f
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
Expand Down