5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-06 10:19:31 +08:00
wails/v3/pkg/application/panic_handler.go
Fabio Massaioli e7c134de4e
[v3] Late service registration and error handling overhaul (#4066)
* Add service registration method

* Fix error handling and formatting in messageprocessor

* Add configurable error handling

* Improve error strings

* Fix service shutdown on macOS

* Add post shutdown hook

* Better fatal errors

* Add startup/shutdown sequence tests

* Improve debug messages

* Update JS runtime

* Update docs

* Update changelog

* Fix log message in clipboard message processor

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Remove panic in RegisterService

* Fix linux tests (hopefully)

* Fix error formatting everywhere

* Fix typo in windows webview

* Tidy example mods

* Set application name in tests

* Fix ubuntu test workflow

* Cleanup template test pipeline

* Fix dev build detection on Go 1.24

* Update template go.mod/sum to Go 1.24

* Remove redundant caching in template tests

* Final format string cleanup

* Fix wails3 tool references

* Fix legacy log calls

* Remove formatJS and simplify format strings

* Fix indirect import

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-02-19 09:27:41 +01:00

105 lines
2.0 KiB
Go

package application
import (
"fmt"
"runtime"
"runtime/debug"
"strings"
"time"
)
func getStackTrace(skipStart int, skipEnd int) string {
// Get all program counters first
pc := make([]uintptr, 32)
n := runtime.Callers(skipStart+1, pc)
if n == 0 {
return ""
}
pc = pc[:n]
frames := runtime.CallersFrames(pc)
// Collect all frames first
var allFrames []runtime.Frame
for {
frame, more := frames.Next()
allFrames = append(allFrames, frame)
if !more {
break
}
}
// Remove frames from the end
if len(allFrames) > skipEnd {
allFrames = allFrames[:len(allFrames)-skipEnd]
}
// Build the output string
var builder strings.Builder
for _, frame := range allFrames {
fmt.Fprintf(&builder, "%s\n\tat %s:%d\n",
frame.Function, frame.File, frame.Line)
}
return builder.String()
}
type handlePanicOptions struct {
skipEnd int
}
type PanicDetails struct {
StackTrace string
Error error
Time time.Time
FullStackTrace string
}
func newPanicDetails(err error, trace string) *PanicDetails {
return &PanicDetails{
Error: err,
Time: time.Now(),
StackTrace: trace,
FullStackTrace: string(debug.Stack()),
}
}
// handlePanic handles any panics
// Returns the error if there was one
func handlePanic(options ...handlePanicOptions) bool {
// Try to recover
e := recover()
if e == nil {
return false
}
// Get the error
err, ok := e.(error)
if !ok {
err = fmt.Errorf("%v", e)
}
// Get the stack trace
var stackTrace string
skipEnd := 0
if len(options) > 0 {
skipEnd = options[0].skipEnd
}
stackTrace = getStackTrace(3, skipEnd)
processPanic(newPanicDetails(err, stackTrace))
return false
}
func processPanic(panicDetails *PanicDetails) {
h := globalApplication.options.PanicHandler
if h != nil {
h(panicDetails)
return
}
defaultPanicHandler(panicDetails)
}
func defaultPanicHandler(panicDetails *PanicDetails) {
globalApplication.fatal("panic error: %w\n%s", panicDetails.Error, panicDetails.StackTrace)
}