Avoid showing panics directly if debug mode is not enabled

This commit is contained in:
Tulir Asokan 2018-03-19 01:18:36 +02:00
parent f288a18a0c
commit 7a4b108b37
4 changed files with 84 additions and 25 deletions

View File

@ -17,8 +17,10 @@
package main package main
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"time"
"maunium.net/go/gomatrix" "maunium.net/go/gomatrix"
"maunium.net/go/gomuks/config" "maunium.net/go/gomuks/config"
@ -29,17 +31,18 @@ import (
"maunium.net/go/tview" "maunium.net/go/tview"
) )
type gomuks struct { type Gomuks struct {
app *tview.Application app *tview.Application
ui *ui.GomuksUI ui *ui.GomuksUI
matrix *matrix.Container matrix *matrix.Container
debug *debug.Pane debug *debug.Pane
config *config.Config debugMode bool
config *config.Config
} }
func NewGomuks(enableDebug bool) *gomuks { func NewGomuks(enableDebug bool) *Gomuks {
configDir := filepath.Join(os.Getenv("HOME"), ".config/gomuks") configDir := filepath.Join(os.Getenv("HOME"), ".config/gomuks")
gmx := &gomuks{ gmx := &Gomuks{
app: tview.NewApplication(), app: tview.NewApplication(),
} }
@ -63,13 +66,14 @@ func NewGomuks(enableDebug bool) *gomuks {
main := gmx.ui.InitViews() main := gmx.ui.InitViews()
if enableDebug { if enableDebug {
main = gmx.debug.Wrap(main) main = gmx.debug.Wrap(main)
gmx.debugMode = true
} }
gmx.app.SetRoot(main, true) gmx.app.SetRoot(main, true)
return gmx return gmx
} }
func (gmx *gomuks) Stop() { func (gmx *Gomuks) Stop() {
gmx.debug.Print("Disconnecting from Matrix...") gmx.debug.Print("Disconnecting from Matrix...")
gmx.matrix.Stop() gmx.matrix.Stop()
gmx.debug.Print("Cleaning up UI...") gmx.debug.Print("Cleaning up UI...")
@ -78,44 +82,54 @@ func (gmx *gomuks) Stop() {
gmx.debug.Print("Saving session...") gmx.debug.Print("Saving session...")
gmx.config.Session.Save() gmx.config.Session.Save()
} }
os.Exit(0)
} }
func (gmx *gomuks) Recover() { func (gmx *Gomuks) Recover() {
if p := recover(); p != nil { if p := recover(); p != nil {
if gmx.App().GetScreen() != nil { if gmx.App().GetScreen() != nil {
gmx.App().GetScreen().Fini() gmx.App().GetScreen().Fini()
} }
panic(p) if gmx.debugMode {
panic(p)
} else {
debug.PrettyPanic()
}
} }
} }
func (gmx *gomuks) Start() { func (gmx *Gomuks) Start() {
if err := gmx.app.Run(); err != nil { if err := gmx.app.Run(); err != nil {
panic(err) panic(err)
} }
} }
func (gmx *gomuks) Matrix() *gomatrix.Client { func (gmx *Gomuks) Matrix() *gomatrix.Client {
return gmx.matrix.Client() return gmx.matrix.Client()
} }
func (gmx *gomuks) MatrixContainer() ifc.MatrixContainer { func (gmx *Gomuks) MatrixContainer() ifc.MatrixContainer {
return gmx.matrix return gmx.matrix
} }
func (gmx *gomuks) App() *tview.Application { func (gmx *Gomuks) App() *tview.Application {
return gmx.app return gmx.app
} }
func (gmx *gomuks) Config() *config.Config { func (gmx *Gomuks) Config() *config.Config {
return gmx.config return gmx.config
} }
func (gmx *gomuks) UI() ifc.GomuksUI { func (gmx *Gomuks) UI() ifc.GomuksUI {
return gmx.ui return gmx.ui
} }
func main() { func main() {
debug := os.Getenv("DEBUG") enableDebug := len(os.Getenv("DEBUG")) > 0
NewGomuks(len(debug) > 0).Start() NewGomuks(enableDebug).Start()
// We use os.Exit() everywhere, so exiting by returning from Start() shouldn't happen.
time.Sleep(5 * time.Second)
fmt.Println("Unexpected exit by return from Gomuks#Start().")
os.Exit(2)
} }

View File

@ -198,13 +198,13 @@ func (c *Container) HandleTyping(evt *gomatrix.Event) {
} }
func (c *Container) SendMessage(roomID, message string) { func (c *Container) SendMessage(roomID, message string) {
c.gmx.Recover() defer c.gmx.Recover()
c.SendTyping(roomID, false) c.SendTyping(roomID, false)
c.client.SendText(roomID, message) c.client.SendText(roomID, message)
} }
func (c *Container) SendTyping(roomID string, typing bool) { func (c *Container) SendTyping(roomID string, typing bool) {
c.gmx.Recover() defer c.gmx.Recover()
ts := time.Now().Unix() ts := time.Now().Unix()
if c.typing > ts && typing { if c.typing > ts && typing {
return return

View File

@ -18,6 +18,11 @@ package debug
import ( import (
"fmt" "fmt"
"io/ioutil"
"os"
"time"
"runtime/debug"
"maunium.net/go/tview" "maunium.net/go/tview"
) )
@ -30,7 +35,7 @@ type Printer interface {
type Pane struct { type Pane struct {
*tview.TextView *tview.TextView
Height int Height int
num int num int
} }
var Default Printer var Default Printer
@ -46,8 +51,8 @@ func NewPane() *Pane {
return &Pane{ return &Pane{
TextView: pane, TextView: pane,
Height: 35, Height: 35,
num: 0, num: 0,
} }
} }
@ -81,3 +86,41 @@ func Print(text ...interface{}) {
Default.Print(text...) Default.Print(text...)
} }
} }
const Oops = ` __________
< Oh noes! >
\
\ ^__^
\ (XX)\_______
(__)\ )\/\
U ||----W |
|| ||`
func PrettyPanic() {
fmt.Println(Oops)
fmt.Println("")
fmt.Println("A fatal error has occurred.")
fmt.Println("")
traceFile := fmt.Sprintf("/tmp/gomuks-panic-%s.txt", time.Now().Format("2006-01-02--15-04-05"))
data := debug.Stack()
err := ioutil.WriteFile(traceFile, data, 0644)
if err != nil {
fmt.Println("Saving the stack trace to", traceFile, "failed:")
fmt.Println("--------------------------------------------------------------------------------")
fmt.Println(err)
fmt.Println("--------------------------------------------------------------------------------")
fmt.Println("")
fmt.Println("You can file an issue at https://github.com/tulir/gomuks/issues.")
fmt.Println("Please provide the file save error (above) and the stack trace of the original error (below) when filing an issue.")
fmt.Println("")
fmt.Println("--------------------------------------------------------------------------------")
debug.PrintStack()
fmt.Println("--------------------------------------------------------------------------------")
} else {
fmt.Println("The stack trace has been saved to", traceFile)
fmt.Println("")
fmt.Println("You can file an issue at https://github.com/tulir/gomuks/issues.")
fmt.Println("Please provide the contents of that file when filing an issue.")
}
os.Exit(1)
}

View File

@ -148,7 +148,7 @@ func (view *MainView) InputDone(key tcell.Key) {
} }
func (view *MainView) HandleCommand(room, command string, args []string) { func (view *MainView) HandleCommand(room, command string, args []string) {
view.gmx.Recover() defer view.gmx.Recover()
debug.Print("Handling command", command, args) debug.Print("Handling command", command, args)
switch command { switch command {
case "/quit": case "/quit":
@ -156,6 +156,8 @@ func (view *MainView) HandleCommand(room, command string, args []string) {
case "/clearcache": case "/clearcache":
view.config.Session.Clear() view.config.Session.Clear()
view.gmx.Stop() view.gmx.Stop()
case "/panic":
panic("This is a test panic.")
case "/part": case "/part":
fallthrough fallthrough
case "/leave": case "/leave":