Improve error message logging from electron (#7130)
This commit is contained in:
@@ -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));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user