mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 08:31:13 -05:00
Fix error logging issues
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
import { toast } from 'sonner';
|
||||
import { logger } from './logger';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { breadcrumbManager } from './errorBreadcrumbs';
|
||||
import { captureEnvironmentContext } from './environmentContext';
|
||||
|
||||
export type ErrorContext = {
|
||||
action: string;
|
||||
@@ -21,9 +24,10 @@ export class AppError extends Error {
|
||||
export const handleError = (
|
||||
error: unknown,
|
||||
context: ErrorContext
|
||||
): string => { // Now returns error ID
|
||||
const errorId = context.metadata?.requestId as string | undefined;
|
||||
const shortErrorId = errorId ? errorId.slice(0, 8) : undefined;
|
||||
): string => {
|
||||
// Generate or use existing error ID
|
||||
const errorId = (context.metadata?.requestId as string) || crypto.randomUUID();
|
||||
const shortErrorId = errorId.slice(0, 8);
|
||||
|
||||
const errorMessage = error instanceof AppError
|
||||
? error.userMessage || error.message
|
||||
@@ -39,15 +43,41 @@ export const handleError = (
|
||||
errorId,
|
||||
});
|
||||
|
||||
// Log to database with breadcrumbs (non-blocking)
|
||||
try {
|
||||
const envContext = captureEnvironmentContext();
|
||||
const breadcrumbs = breadcrumbManager.getAll();
|
||||
|
||||
// Fire-and-forget database logging
|
||||
supabase.rpc('log_request_metadata', {
|
||||
p_request_id: errorId,
|
||||
p_user_id: context.userId || undefined,
|
||||
p_endpoint: context.action,
|
||||
p_method: 'ERROR',
|
||||
p_status_code: 500,
|
||||
p_error_type: error instanceof Error ? error.name : 'UnknownError',
|
||||
p_error_message: errorMessage,
|
||||
p_error_stack: error instanceof Error ? error.stack : undefined,
|
||||
p_user_agent: navigator.userAgent,
|
||||
p_breadcrumbs: JSON.stringify(breadcrumbs),
|
||||
p_timezone: envContext.timezone,
|
||||
p_referrer: document.referrer || undefined,
|
||||
}).then(({ error: dbError }) => {
|
||||
if (dbError) {
|
||||
logger.error('Failed to log error to database', { dbError });
|
||||
}
|
||||
});
|
||||
} catch (logError) {
|
||||
logger.error('Failed to capture error context', { logError });
|
||||
}
|
||||
|
||||
// Show user-friendly toast with error ID
|
||||
toast.error(context.action, {
|
||||
description: shortErrorId
|
||||
? `${errorMessage}\n\nReference ID: ${shortErrorId}`
|
||||
: errorMessage,
|
||||
description: `${errorMessage}\n\nReference ID: ${shortErrorId}`,
|
||||
duration: 5000,
|
||||
});
|
||||
|
||||
return errorId || 'unknown';
|
||||
return errorId;
|
||||
};
|
||||
|
||||
export const handleSuccess = (
|
||||
|
||||
118
src/lib/supabaseClient.ts
Normal file
118
src/lib/supabaseClient.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Enhanced Supabase Client with Automatic Breadcrumb Tracking
|
||||
* Wraps the standard Supabase client to add automatic API call tracking
|
||||
*/
|
||||
|
||||
import { supabase as baseSupabase } from '@/integrations/supabase/client';
|
||||
import { breadcrumb } from './errorBreadcrumbs';
|
||||
|
||||
// Create a proxy that tracks API calls
|
||||
export const supabase = new Proxy(baseSupabase, {
|
||||
get(target, prop) {
|
||||
const value = target[prop as keyof typeof target];
|
||||
|
||||
// Track database operations
|
||||
if (prop === 'from') {
|
||||
return (table: string) => {
|
||||
const query = (target as any).from(table);
|
||||
|
||||
// Wrap query methods to track breadcrumbs
|
||||
return new Proxy(query, {
|
||||
get(queryTarget, queryProp) {
|
||||
const queryValue = queryTarget[queryProp as string];
|
||||
|
||||
if (typeof queryValue === 'function') {
|
||||
return async (...args: any[]) => {
|
||||
const method = String(queryProp).toUpperCase();
|
||||
breadcrumb.apiCall(`/table/${table}`, method);
|
||||
|
||||
try {
|
||||
const result = await queryValue.apply(queryTarget, args);
|
||||
|
||||
if (result.error) {
|
||||
breadcrumb.apiCall(`/table/${table}`, method, 400);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
breadcrumb.apiCall(`/table/${table}`, method, 500);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return queryValue;
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Track RPC calls
|
||||
if (prop === 'rpc') {
|
||||
return async (functionName: string, params?: any) => {
|
||||
breadcrumb.apiCall(`/rpc/${functionName}`, 'RPC');
|
||||
|
||||
try {
|
||||
const result = await (target as any).rpc(functionName, params);
|
||||
|
||||
if (result.error) {
|
||||
breadcrumb.apiCall(`/rpc/${functionName}`, 'RPC', 400);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
breadcrumb.apiCall(`/rpc/${functionName}`, 'RPC', 500);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Track storage operations
|
||||
if (prop === 'storage') {
|
||||
const storage = (target as any).storage;
|
||||
|
||||
return new Proxy(storage, {
|
||||
get(storageTarget, storageProp) {
|
||||
const storageValue = storageTarget[storageProp];
|
||||
|
||||
if (storageProp === 'from') {
|
||||
return (bucket: string) => {
|
||||
const bucketOps = storageValue.call(storageTarget, bucket);
|
||||
|
||||
return new Proxy(bucketOps, {
|
||||
get(bucketTarget, bucketProp) {
|
||||
const bucketValue = bucketTarget[bucketProp as string];
|
||||
|
||||
if (typeof bucketValue === 'function') {
|
||||
return async (...args: any[]) => {
|
||||
breadcrumb.apiCall(`/storage/${bucket}`, String(bucketProp).toUpperCase());
|
||||
|
||||
try {
|
||||
const result = await bucketValue.apply(bucketTarget, args);
|
||||
|
||||
if (result.error) {
|
||||
breadcrumb.apiCall(`/storage/${bucket}`, String(bucketProp).toUpperCase(), 400);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
breadcrumb.apiCall(`/storage/${bucket}`, String(bucketProp).toUpperCase(), 500);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return bucketValue;
|
||||
},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return storageValue;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user