mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 08:51:13 -05:00
Implement client-side error timing
This commit is contained in:
@@ -57,8 +57,7 @@ Timestamp: ${format(new Date(error.created_at), 'PPpp')}
|
|||||||
Type: ${error.error_type}
|
Type: ${error.error_type}
|
||||||
Endpoint: ${error.endpoint}
|
Endpoint: ${error.endpoint}
|
||||||
Method: ${error.method}
|
Method: ${error.method}
|
||||||
Status: ${error.status_code}
|
Status: ${error.status_code}${error.duration_ms != null ? `\nDuration: ${error.duration_ms}ms` : ''}
|
||||||
Duration: ${error.duration_ms}ms
|
|
||||||
|
|
||||||
Error Message:
|
Error Message:
|
||||||
${error.error_message}
|
${error.error_message}
|
||||||
@@ -117,10 +116,12 @@ ${error.error_stack ? `Stack Trace:\n${error.error_stack}` : ''}
|
|||||||
<label className="text-sm font-medium">Status Code</label>
|
<label className="text-sm font-medium">Status Code</label>
|
||||||
<p className="text-sm">{error.status_code}</p>
|
<p className="text-sm">{error.status_code}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
{error.duration_ms != null && (
|
||||||
<label className="text-sm font-medium">Duration</label>
|
<div>
|
||||||
<p className="text-sm">{error.duration_ms}ms</p>
|
<label className="text-sm font-medium">Duration</label>
|
||||||
</div>
|
<p className="text-sm">{error.duration_ms}ms</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{error.user_id && (
|
{error.user_id && (
|
||||||
<div>
|
<div>
|
||||||
<label className="text-sm font-medium">User ID</label>
|
<label className="text-sm font-medium">User ID</label>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export type ErrorContext = {
|
|||||||
action: string;
|
action: string;
|
||||||
userId?: string;
|
userId?: string;
|
||||||
metadata?: Record<string, unknown>;
|
metadata?: Record<string, unknown>;
|
||||||
|
duration?: number; // Optional: milliseconds the operation took
|
||||||
};
|
};
|
||||||
|
|
||||||
export class AppError extends Error {
|
export class AppError extends Error {
|
||||||
@@ -78,6 +79,7 @@ export const handleError = (
|
|||||||
p_breadcrumbs: JSON.stringify(breadcrumbs),
|
p_breadcrumbs: JSON.stringify(breadcrumbs),
|
||||||
p_timezone: envContext.timezone,
|
p_timezone: envContext.timezone,
|
||||||
p_referrer: document.referrer || undefined,
|
p_referrer: document.referrer || undefined,
|
||||||
|
p_duration_ms: context.duration,
|
||||||
}).then(({ error: dbError }) => {
|
}).then(({ error: dbError }) => {
|
||||||
if (dbError) {
|
if (dbError) {
|
||||||
logger.error('Failed to log error to database', { dbError });
|
logger.error('Failed to log error to database', { dbError });
|
||||||
@@ -161,6 +163,7 @@ export const handleNonCriticalError = (
|
|||||||
p_breadcrumbs: JSON.stringify(breadcrumbs),
|
p_breadcrumbs: JSON.stringify(breadcrumbs),
|
||||||
p_timezone: envContext.timezone,
|
p_timezone: envContext.timezone,
|
||||||
p_referrer: document.referrer || undefined,
|
p_referrer: document.referrer || undefined,
|
||||||
|
p_duration_ms: context.duration,
|
||||||
}).then(({ error: dbError }) => {
|
}).then(({ error: dbError }) => {
|
||||||
if (dbError) {
|
if (dbError) {
|
||||||
logger.error('Failed to log non-critical error to database', { 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'
|
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<T>(
|
||||||
|
fn: () => Promise<T>,
|
||||||
|
errorContext: Omit<ErrorContext, 'duration'>
|
||||||
|
): Promise<T> {
|
||||||
|
const start = performance.now();
|
||||||
|
try {
|
||||||
|
return await fn();
|
||||||
|
} catch (error) {
|
||||||
|
const duration = Math.round(performance.now() - start);
|
||||||
|
handleError(error, { ...errorContext, duration });
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ export default function ErrorMonitoring() {
|
|||||||
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
||||||
<span>ID: {error.request_id.slice(0, 8)}</span>
|
<span>ID: {error.request_id.slice(0, 8)}</span>
|
||||||
<span>{format(new Date(error.created_at), 'PPp')}</span>
|
<span>{format(new Date(error.created_at), 'PPp')}</span>
|
||||||
<span>{error.duration_ms}ms</span>
|
{error.duration_ms != null && <span>{error.duration_ms}ms</span>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user