返回 DeepSeek-Reasonix
wails_logger.go
根目录 / desktop / wails_logger.go
1 package main
2
3 import (
4 "fmt"
5 goruntime "runtime"
6 "strconv"
7 "strings"
8 "sync"
9 "time"
10
11 "github.com/wailsapp/wails/v2/pkg/logger"
12 )
13
14 type crashCaptureLogger struct {
15 delegate logger.Logger
16 app *App
17 webView2Failures webView2FailureTracker
18 }
19
20 const webView2FailureReportCooldown = 10 * time.Minute
21
22 type webView2FailureTracker struct {
23 mu sync.Mutex
24 counts map[int]int
25 lastReported map[int]time.Time
26 }
27
28 func (t *webView2FailureTracker) observe(kind int, now time.Time) (occurrence int, shouldReport bool) {
29 t.mu.Lock()
30 defer t.mu.Unlock()
31 if t.counts == nil {
32 t.counts = make(map[int]int)
33 t.lastReported = make(map[int]time.Time)
34 }
35 t.counts[kind]++
36 last := t.lastReported[kind]
37 if last.IsZero() || now.Sub(last) >= webView2FailureReportCooldown {
38 t.lastReported[kind] = now
39 return t.counts[kind], true
40 }
41 return t.counts[kind], false
42 }
43
44 func newCrashCaptureLogger(app *App) logger.Logger {
45 return &crashCaptureLogger{delegate: logger.NewDefaultLogger(), app: app}
46 }
47
48 func (l *crashCaptureLogger) Print(message string) { l.delegate.Print(message) }
49 func (l *crashCaptureLogger) Trace(message string) { l.delegate.Trace(message) }
50 func (l *crashCaptureLogger) Debug(message string) { l.delegate.Debug(message) }
51 func (l *crashCaptureLogger) Info(message string) { l.delegate.Info(message) }
52 func (l *crashCaptureLogger) Warning(message string) { l.delegate.Warning(message) }
53 func (l *crashCaptureLogger) Fatal(message string) {
54 l.captureWebView2Failure(message)
55 l.delegate.Fatal(message)
56 }
57 func (l *crashCaptureLogger) Error(message string) {
58 l.captureWebView2Failure(message)
59 l.delegate.Error(message)
60 }
61
62 func (l *crashCaptureLogger) captureWebView2Failure(message string) {
63 if goruntime.GOOS != "windows" {
64 return
65 }
66 kind, ok := parseWebView2ProcessFailure(message)
67 if !ok {
68 return
69 }
70 if l.app != nil {
71 l.app.recordDiagnosticMetric("desktop_webview2_failure", webView2ProcessKindBucket(kind))
72 }
73 occurrence, shouldReport := l.webView2Failures.observe(kind, time.Now())
74 if !shouldReport {
75 return
76 }
77 report := webView2ProcessFailureReportWithContext(kind, occurrence, webView2RuntimeVersion())
78 _ = writePendingReport(report, true)
79 }
80
81 func parseWebView2ProcessFailure(message string) (int, bool) {
82 const marker = "Process failed with kind "
83 index := strings.LastIndex(message, marker)
84 if index < 0 {
85 return 0, false
86 }
87 value := strings.TrimSpace(message[index+len(marker):])
88 kind, err := strconv.Atoi(value)
89 return kind, err == nil && kind >= 0 && kind <= 9
90 }
91
92 func webView2ProcessKindBucket(kind int) string {
93 names := []string{
94 "browser_process_exited",
95 "render_process_exited",
96 "render_process_unresponsive",
97 "frame_render_process_exited",
98 "utility_process_exited",
99 "sandbox_helper_process_exited",
100 "gpu_process_exited",
101 "ppapi_plugin_process_exited",
102 "ppapi_broker_process_exited",
103 "unknown_process_exited",
104 }
105 if kind < 0 || kind >= len(names) {
106 return "unknown"
107 }
108 return names[kind]
109 }
110
111 func webView2ProcessFailureReportWithContext(kind, occurrence int, runtimeVersion string) crashReport {
112 bucket := webView2ProcessKindBucket(kind)
113 report := baseCrashReport("crash")
114 report.SchemaVersion = 2
115 report.Source = "webview2.process"
116 report.Label = "windows.webview2.process_failed"
117 report.ErrorType = "WebView2ProcessFailed"
118 report.ErrorMessage = sanitizeCrashText(fmt.Sprintf("WebView2 process failed: %s.", bucket), maxCrashFieldBytes)
119 report.TopFrame = "webview2.process." + bucket
120 report.FingerprintHint = "windows.webview2." + bucket
121 report.OccurredAt = time.Now().UTC().Format(time.RFC3339)
122 runtimeVersion = sanitizeCrashField(runtimeVersion, 128)
123 if runtimeVersion == "" {
124 runtimeVersion = "unavailable"
125 }
126 report.Message = sanitizeCrashText(fmt.Sprintf(`[windows.webview2.process_failed]
127
128 WebView2 reported a failed child process.
129
130 process kind: %s
131 kind code: %d
132 runtime version: %s
133 same-process occurrence: %d
134 exit code: unavailable from the current Wails ProcessFailed callback
135 GPU/driver: unavailable from the current Wails ProcessFailed callback`, bucket, kind, runtimeVersion, occurrence), maxCrashDetailBytes)
136 return report
137 }
138
138 lines GO