Generate crash report txt and webpage

The last 100 lines of logs are now cached, and when a crash occurs, they
are saved to a file in the temp directory ("/tmp" on *nix), and pretty
HTML version is also created and opened in the browser.
* Currently only handles panics, will be included in more places soon
* Copy button and button to generate a GH issue will be added
This commit is contained in:
Harvey Tindall
2021-06-11 21:56:53 +01:00
parent 2f501697db
commit f0f4e8118e
13 changed files with 3797 additions and 45 deletions

3
linecache/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module github.com/hrfee/jfa-go/linecache
go 1.16

66
linecache/linecache.go Normal file
View File

@@ -0,0 +1,66 @@
// Package linecache provides a writer that stores n lines of text at once, overwriting old content as it reaches its capacity. Its contents can be read from with a String() method.
package linecache
import (
"strings"
"sync"
)
// LineCache provides an io.Writer that stores a fixed number of lines of text.
type LineCache struct {
count int
lines [][]byte
current int
lock *sync.Mutex
}
// NewLineCache returns a new line cache of capacity (n) lines.
func NewLineCache(n int) *LineCache {
return &LineCache{
current: 0,
count: n,
lines: make([][]byte, n),
lock: &sync.Mutex{},
}
}
// Write writes a given byte array to the cache.
func (l *LineCache) Write(p []byte) (n int, err error) {
l.lock.Lock()
defer l.lock.Unlock()
lines := strings.Split(string(p), "\n")
for _, line := range lines {
if string(line) == "" {
continue
}
if l.current == l.count {
l.current = 0
}
l.lines[l.current] = []byte(line)
l.current++
}
n = len(p)
return
}
// String returns a string representation of the cache contents.
func (l *LineCache) String() string {
i := 0
if l.lines[l.count-1] != nil && l.current != l.count {
i = l.current
}
out := ""
for {
if l.lines[i] == nil {
return out
}
out += string(l.lines[i]) + "\n"
i++
if i == l.current {
return out
}
if i == l.count {
i = 0
}
}
}

View File

@@ -0,0 +1,17 @@
package linecache
import (
"fmt"
"strings"
"testing"
"time"
)
func Test(t *testing.T) {
wr := NewLineCache(10)
for i := 10; i < 50; i++ {
fmt.Fprintln(wr, i)
fmt.Print(strings.ReplaceAll(wr.String(), "\n", " "), "\n")
time.Sleep(time.Second)
}
}