Improve error message logging from electron (#7130)

This commit is contained in:
Zane
2026-02-12 08:59:02 -08:00
committed by GitHub
parent ac2a569868
commit 2303e46e8d
6 changed files with 29 additions and 26 deletions
+3 -2
View File
@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { Button } from './ui/button'; import { Button } from './ui/button';
import { AlertTriangle } from 'lucide-react'; import { AlertTriangle } from 'lucide-react';
import { errorMessage } from '../utils/conversionUtils'; import { errorMessage, formatErrorForLogging } from '../utils/conversionUtils';
import { trackErrorWithContext, trackEvent, getErrorType } from '../utils/analytics'; import { trackErrorWithContext, trackEvent, getErrorType } from '../utils/analytics';
function getCurrentPage(): string { function getCurrentPage(): string {
@@ -10,7 +10,8 @@ function getCurrentPage(): string {
// Capture unhandled promise rejections // Capture unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => { window.addEventListener('unhandledrejection', (event) => {
window.electron.logInfo(`[UNHANDLED REJECTION] ${event.reason}`); const reasonStr = formatErrorForLogging(event.reason);
window.electron.logInfo(`[UNHANDLED REJECTION] ${reasonStr}`);
trackErrorWithContext(event.reason, { trackErrorWithContext(event.reason, {
component: 'global', component: 'global',
page: getCurrentPage(), page: getCurrentPage(),
@@ -9,6 +9,7 @@ import {
DialogHeader, DialogHeader,
DialogTitle, DialogTitle,
} from '../../ui/dialog'; } from '../../ui/dialog';
import { errorMessage } from '../../../utils/conversionUtils';
const HelpText = () => ( const HelpText = () => (
<div className="text-sm flex-col space-y-4 text-text-muted"> <div className="text-sm flex-col space-y-4 text-text-muted">
@@ -39,7 +40,7 @@ const HelpText = () => (
const ErrorDisplay = ({ error }: { error: Error }) => ( const ErrorDisplay = ({ error }: { error: Error }) => (
<div className="text-sm text-text-muted"> <div className="text-sm text-text-muted">
<div className="text-red-600">Error reading .goosehints file: {JSON.stringify(error)}</div> <div className="text-red-600">Error reading .goosehints file: {errorMessage(error)}</div>
</div> </div>
); );
@@ -19,20 +19,7 @@ import { useModelAndProvider } from '../../../ModelAndProviderContext';
import { AlertTriangle, LogIn } from 'lucide-react'; import { AlertTriangle, LogIn } from 'lucide-react';
import { ProviderDetails, removeCustomProvider, configureProviderOauth } from '../../../../api'; import { ProviderDetails, removeCustomProvider, configureProviderOauth } from '../../../../api';
import { Button } from '../../../../components/ui/button'; import { Button } from '../../../../components/ui/button';
import { errorMessage } from '../../../../utils/conversionUtils';
const formatErrorMessage = (error: unknown): string => {
if (error instanceof Error) {
return error.message;
}
if (typeof error === 'string') {
return error;
}
try {
return JSON.stringify(error);
} catch {
return String(error);
}
};
interface ProviderConfigurationModalProps { interface ProviderConfigurationModalProps {
provider: ProviderDetails; provider: ProviderDetails;
@@ -87,7 +74,7 @@ export default function ProviderConfigurationModal({
onClose(); onClose();
} }
} catch (err) { } catch (err) {
setError(`OAuth login failed: ${formatErrorMessage(err)}`); setError(`OAuth login failed: ${errorMessage(err)}`);
} finally { } finally {
setIsOAuthLoading(false); setIsOAuthLoading(false);
} }
@@ -130,7 +117,7 @@ export default function ProviderConfigurationModal({
onClose(); onClose();
} }
} catch (error) { } catch (error) {
setError(formatErrorMessage(error)); setError(errorMessage(error));
} }
}; };
+3 -3
View File
@@ -28,7 +28,7 @@ import { expandTilde } from './utils/pathUtils';
import log from './utils/logger'; import log from './utils/logger';
import { ensureWinShims } from './utils/winShims'; import { ensureWinShims } from './utils/winShims';
import { addRecentDir, loadRecentDirs } from './utils/recentDirs'; import { addRecentDir, loadRecentDirs } from './utils/recentDirs';
import { formatAppName, errorMessage } from './utils/conversionUtils'; import { formatAppName, errorMessage, formatErrorForLogging } from './utils/conversionUtils';
import type { Settings } from './utils/settings'; import type { Settings } from './utils/settings';
import { defaultKeyboardShortcuts, getKeyboardShortcuts } from './utils/settings'; import { defaultKeyboardShortcuts, getKeyboardShortcuts } from './utils/settings';
import * as crypto from 'crypto'; import * as crypto from 'crypto';
@@ -1116,12 +1116,12 @@ const handleFatalError = (error: Error) => {
}; };
process.on('uncaughtException', (error) => { process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error); console.error('Uncaught Exception:', formatErrorForLogging(error));
handleFatalError(error); handleFatalError(error);
}); });
process.on('unhandledRejection', (error) => { process.on('unhandledRejection', (error) => {
console.error('Unhandled Rejection:', error); console.error('Unhandled Rejection:', formatErrorForLogging(error));
handleFatalError(error instanceof Error ? error : new Error(String(error))); handleFatalError(error instanceof Error ? error : new Error(String(error)));
}); });
+4 -4
View File
@@ -241,10 +241,10 @@ export function trackPageView(page: string, referrer?: string): void {
export function trackError( export function trackError(
errorType: string, errorType: string,
options: { options: {
component?: string; // React component name component?: string;
page?: string; // Current route/page page?: string;
action?: string; // What user was doing action?: string;
stackSummary?: string; // Use getStackSummary() to generate stackSummary?: string;
recoverable?: boolean; recoverable?: boolean;
} = {} } = {}
): void { ): void {
+14
View File
@@ -22,6 +22,20 @@ export function errorMessage(err: Error | unknown, default_value?: string) {
} }
} }
export function formatErrorForLogging(error: unknown): string {
if (error instanceof Error) {
return `${error.name}: ${error.message}${error.stack ? `\n${error.stack}` : ''}`;
}
if (typeof error === 'object' && error !== null) {
try {
return JSON.stringify(error, null, 2);
} catch {
return String(error);
}
}
return String(error);
}
export async function compressImageDataUrl(dataUrl: string): Promise<string> { export async function compressImageDataUrl(dataUrl: string): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const img = new globalThis.Image(); const img = new globalThis.Image();