Skip to content

Commit

Permalink
Catch errors in goroutines and log them
Browse files Browse the repository at this point in the history
  • Loading branch information
walles committed Aug 10, 2024
1 parent 3b5b2ff commit 6cf1223
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 5 deletions.
12 changes: 12 additions & 0 deletions m/pager.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,10 @@ func (p *Pager) StartPaging(screen twin.Screen, chromaStyle *chroma.Style, chrom
p.marks = make(map[rune]scrollPosition)

go func() {
defer func() {
panicHandler("StartPaging()/moreLinesAvailable", recover())
}()

for range p.reader.moreLinesAdded {
// Notify the main loop about the new lines so it can show them
screen.Events() <- eventMoreLinesAvailable{}
Expand All @@ -337,6 +341,10 @@ func (p *Pager) StartPaging(screen twin.Screen, chromaStyle *chroma.Style, chrom
}()

go func() {
defer func() {
panicHandler("StartPaging()/spinner", recover())
}()

// Spin the spinner as long as contents is still loading
spinnerFrames := [...]string{"/.\\", "-o-", "\\O/", "| |"}
spinnerIndex := 0
Expand All @@ -359,6 +367,10 @@ func (p *Pager) StartPaging(screen twin.Screen, chromaStyle *chroma.Style, chrom
}()

go func() {
defer func() {
panicHandler("StartPaging()/maybeDone", recover())
}()

for range p.reader.maybeDone {
screen.Events() <- eventMaybeDone{}
}
Expand Down
17 changes: 17 additions & 0 deletions m/panicHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package m

// NOTE: This file should be identical to twin/panicHandler.go

import (
log "github.com/sirupsen/logrus"
)

func panicHandler(goroutineName string, recoverResult any) {
if recoverResult == nil {
return
}

log.WithFields(log.Fields{
"recoverResult": recoverResult,
}).Error("Goroutine panicked: " + goroutineName)
}
12 changes: 8 additions & 4 deletions m/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ func NewReaderFromStream(name string, reader io.Reader, style chroma.Style, form
// then used for pre-allocating the lines slice, which improves large file
// loading performance.
//
// If lexer is not nil, the file will be highlighted after being fully read.
// If lexer is set, the file will be highlighted after being fully read.
//
// Note that you must call reader.SetStyleForHighlighting() after this to get
// highlighting.
Expand All @@ -364,9 +364,13 @@ func newReaderFromStream(reader io.Reader, originalFileName *string, formatter c
done: &done,
}

// FIXME: Make sure that if we panic somewhere inside of this goroutine,
// the main program terminates and prints our panic stack trace.
go returnMe.readStream(reader, formatter, lexer)
go func() {
defer func() {
panicHandler("newReaderFromStream()/readStream()", recover())
}()

returnMe.readStream(reader, formatter, lexer)
}()

return &returnMe
}
Expand Down
4 changes: 4 additions & 0 deletions m/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ func (p *Pager) findFirstHit(startPosition linenumbers.LineNumber, beforePositio
}

go func(i int, searchStart linenumbers.LineNumber, chunkBefore *linenumbers.LineNumber) {
defer func() {
panicHandler("findFirstHit()/chunkSearch", recover())
}()

findings[i] <- p._findFirstHit(searchStart, chunkBefore, backwards)
}(i, searchStart, chunkBefore)
}
Expand Down
17 changes: 17 additions & 0 deletions twin/panicHandler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package twin

// NOTE: This file should be identical to m/panicHandler.go

import (
log "github.com/sirupsen/logrus"
)

func panicHandler(goroutineName string, recoverResult any) {
if recoverResult == nil {
return
}

log.WithFields(log.Fields{
"recoverResult": recoverResult,
}).Error("Goroutine panicked: " + goroutineName)
}
4 changes: 4 additions & 0 deletions twin/screen-setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ func (screen *UnixScreen) setupSigwinchNotification() {
sigwinch := make(chan os.Signal, 1)
signal.Notify(sigwinch, syscall.SIGWINCH)
go func() {
defer func() {
panicHandler("setupSigwinchNotification()/SIGWINCH", recover())
}()

for {
// Await window resize signal
<-sigwinch
Expand Down
4 changes: 4 additions & 0 deletions twin/screen-setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func TestInterruptableReader_blockedOnReadImmediate(t *testing.T) {
}
readResultChan := make(chan readResult)
go func() {
defer func() {
panicHandler("TestInterruptableReader_blockedOnReadImmediate()", recover())
}()

buffer := make([]byte, 1)
n, err := testMe.Read(buffer)
readResultChan <- readResult{n, err}
Expand Down
8 changes: 7 additions & 1 deletion twin/screen.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,13 @@ func NewScreenWithMouseModeAndColorType(mouseMode MouseMode, terminalColorCount

screen.hideCursor(true)

go screen.mainLoop()
go func() {
defer func() {
panicHandler("NewScreenWithMouseModeAndColorType()/mainLoop()", recover())
}()

screen.mainLoop()
}()

return &screen, nil
}
Expand Down
4 changes: 4 additions & 0 deletions twin/screen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,10 @@ func TestInterruptableReader_blockedOnRead(t *testing.T) {
}
readResultChan := make(chan readResult)
go func() {
defer func() {
panicHandler("TestInterruptableReader_blockedOnRead()", recover())
}()

buffer := make([]byte, 1)
n, err := testMe.Read(buffer)
readResultChan <- readResult{n, err}
Expand Down

0 comments on commit 6cf1223

Please sign in to comment.