diff --git a/src/components/admin/ErrorDetailsModal.tsx b/src/components/admin/ErrorDetailsModal.tsx
index 657d0897..d9bd92c4 100644
--- a/src/components/admin/ErrorDetailsModal.tsx
+++ b/src/components/admin/ErrorDetailsModal.tsx
@@ -57,8 +57,7 @@ Timestamp: ${format(new Date(error.created_at), 'PPpp')}
Type: ${error.error_type}
Endpoint: ${error.endpoint}
Method: ${error.method}
-Status: ${error.status_code}
-Duration: ${error.duration_ms}ms
+Status: ${error.status_code}${error.duration_ms != null ? `\nDuration: ${error.duration_ms}ms` : ''}
Error Message:
${error.error_message}
@@ -117,10 +116,12 @@ ${error.error_stack ? `Stack Trace:\n${error.error_stack}` : ''}
{error.status_code}
-
-
-
{error.duration_ms}ms
-
+ {error.duration_ms != null && (
+
+
+
{error.duration_ms}ms
+
+ )}
{error.user_id && (
diff --git a/src/lib/errorHandler.ts b/src/lib/errorHandler.ts
index 4ef0909d..87a9f250 100644
--- a/src/lib/errorHandler.ts
+++ b/src/lib/errorHandler.ts
@@ -8,6 +8,7 @@ export type ErrorContext = {
action: string;
userId?: string;
metadata?: Record
;
+ duration?: number; // Optional: milliseconds the operation took
};
export class AppError extends Error {
@@ -78,6 +79,7 @@ export const handleError = (
p_breadcrumbs: JSON.stringify(breadcrumbs),
p_timezone: envContext.timezone,
p_referrer: document.referrer || undefined,
+ p_duration_ms: context.duration,
}).then(({ error: dbError }) => {
if (dbError) {
logger.error('Failed to log error to database', { dbError });
@@ -161,6 +163,7 @@ export const handleNonCriticalError = (
p_breadcrumbs: JSON.stringify(breadcrumbs),
p_timezone: envContext.timezone,
p_referrer: document.referrer || undefined,
+ p_duration_ms: context.duration,
}).then(({ error: dbError }) => {
if (dbError) {
logger.error('Failed to log non-critical error to database', { dbError });
@@ -202,3 +205,21 @@ export function hasErrorCode(error: unknown): error is { code: string } {
typeof (error as { code: unknown }).code === 'string'
);
}
+
+/**
+ * Helper to wrap async operations with automatic duration tracking
+ * Use this for operations where you want to track how long they took before failing
+ */
+export async function withErrorTiming(
+ fn: () => Promise,
+ errorContext: Omit
+): Promise {
+ const start = performance.now();
+ try {
+ return await fn();
+ } catch (error) {
+ const duration = Math.round(performance.now() - start);
+ handleError(error, { ...errorContext, duration });
+ throw error;
+ }
+}
diff --git a/src/pages/admin/ErrorMonitoring.tsx b/src/pages/admin/ErrorMonitoring.tsx
index 0361af74..70894977 100644
--- a/src/pages/admin/ErrorMonitoring.tsx
+++ b/src/pages/admin/ErrorMonitoring.tsx
@@ -165,7 +165,7 @@ export default function ErrorMonitoring() {
ID: {error.request_id.slice(0, 8)}
{format(new Date(error.created_at), 'PPp')}
- {error.duration_ms}ms
+ {error.duration_ms != null && {error.duration_ms}ms}