mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-14 22:55:48 +01:00
The panic handling has been ported to v2. Here's a summary of the changes:
## Summary of Changes
**1. Created `v2/internal/frontend/desktop/linux/panic_handler.go`**
- Ported the panic recovery logic from v3
- Includes `getStackTrace()` function for generating readable stack traces
- `handlePanic()` function that recovers from panics and either calls the custom handler or logs the error
**2. Added to `v2/pkg/options/options.go`**
- Added `PanicDetails` struct with `StackTrace`, `Error`, `Time`, and `FullStackTrace` fields
- Added `PanicHandler` type: `func(*PanicDetails)`
- Added `PanicHandler` field to the `App` struct with documentation
**3. Modified `v2/internal/frontend/desktop/linux/frontend.go`**
- Added `defer handlePanic(f.frontendOptions.PanicHandler, f.logger)` to the goroutine in `processMessage()` (line 468)
## Usage Example
Users can now configure a custom panic handler in their v2 Wails application:
```go
app := wails.Run(&options.App{
Title: "My App",
// ... other options
PanicHandler: func(details *options.PanicDetails) {
// Custom panic handling logic
log.Printf("Panic occurred at %v: %v\n%s",
details.Time,
details.Error,
details.StackTrace)
// Could show error dialog, send to error tracking service, etc.
},
})
```
If no `PanicHandler` is set, panics will be logged via the application logger and the application will continue running instead of crashing with a signal handler error.
This commit is contained in:
parent
5d39f1aa9a
commit
ca206452cd
3 changed files with 121 additions and 0 deletions
|
|
@ -501,6 +501,8 @@ func (f *Frontend) processMessage(message string) {
|
|||
}
|
||||
|
||||
go func() {
|
||||
defer handlePanic(f.frontendOptions.PanicHandler, f.logger)
|
||||
|
||||
result, err := f.dispatcher.ProcessMessage(message, f)
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
|
|
|
|||
100
v2/internal/frontend/desktop/linux/panic_handler.go
Normal file
100
v2/internal/frontend/desktop/linux/panic_handler.go
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package linux
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func newPanicDetails(err error, trace string) *options.PanicDetails {
|
||||
return &options.PanicDetails{
|
||||
Error: err,
|
||||
Time: time.Now(),
|
||||
StackTrace: trace,
|
||||
FullStackTrace: string(debug.Stack()),
|
||||
}
|
||||
}
|
||||
|
||||
// handlePanic recovers from panics and processes them through the configured handler.
|
||||
// Returns true if a panic was recovered.
|
||||
func handlePanic(handler options.PanicHandler, logger interface{ Error(string, ...interface{}) }, opts ...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(opts) > 0 {
|
||||
skipEnd = opts[0].skipEnd
|
||||
}
|
||||
stackTrace = getStackTrace(3, skipEnd)
|
||||
|
||||
panicDetails := newPanicDetails(err, stackTrace)
|
||||
|
||||
// Use custom handler if provided
|
||||
if handler != nil {
|
||||
handler(panicDetails)
|
||||
return true
|
||||
}
|
||||
|
||||
// Default behavior: log the panic
|
||||
if logger != nil {
|
||||
logger.Error("panic error: %v\n%s", panicDetails.Error, panicDetails.StackTrace)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/linux"
|
||||
|
|
@ -69,6 +70,12 @@ type App struct {
|
|||
// ErrorFormatter overrides the formatting of errors returned by backend methods
|
||||
ErrorFormatter ErrorFormatter
|
||||
|
||||
// PanicHandler is called when a panic occurs in a bound method.
|
||||
// If not set, the panic will be logged and the application will continue.
|
||||
// This is particularly useful on Linux where panics in cgo callbacks
|
||||
// can cause signal handler issues.
|
||||
PanicHandler PanicHandler
|
||||
|
||||
// CSS property to test for draggable elements. Default "--wails-draggable"
|
||||
CSSDragProperty string
|
||||
|
||||
|
|
@ -108,6 +115,18 @@ type App struct {
|
|||
|
||||
type ErrorFormatter func(error) any
|
||||
|
||||
// PanicDetails contains information about a panic that occurred in a bound method
|
||||
type PanicDetails struct {
|
||||
StackTrace string
|
||||
Error error
|
||||
Time time.Time
|
||||
FullStackTrace string
|
||||
}
|
||||
|
||||
// PanicHandler is a function that handles panics in bound methods.
|
||||
// If not set, panics will be logged to the application logger.
|
||||
type PanicHandler func(*PanicDetails)
|
||||
|
||||
type RGBA struct {
|
||||
R uint8 `json:"r"`
|
||||
G uint8 `json:"g"`
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue