/** * Error Logging Service * Centralized error logging that can integrate with Sentry or other services */ export interface ErrorContext { componentStack?: string; errorBoundary?: string; userId?: string; userEmail?: string; url?: string; userAgent?: string; timestamp?: string; [key: string]: any; } export enum ErrorSeverity { FATAL = 'fatal', ERROR = 'error', WARNING = 'warning', INFO = 'info', DEBUG = 'debug', } class ErrorLogger { private enabled: boolean; private environment: string; constructor() { this.enabled = process.env.NEXT_PUBLIC_SENTRY_ENABLED === 'true'; this.environment = process.env.NODE_ENV || 'development'; } /** * Initialize error logging service (e.g., Sentry) */ init() { if (!this.enabled) { console.log('[ErrorLogger] Error tracking disabled'); return; } // TODO: Initialize Sentry // import * as Sentry from '@sentry/nextjs'; // Sentry.init({ // dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, // environment: this.environment, // tracesSampleRate: 0.1, // beforeSend(event) { // // Filter out sensitive data // return event; // }, // }); console.log('[ErrorLogger] Error tracking initialized'); } /** * Log an error with context */ logError(error: Error, context?: ErrorContext, severity: ErrorSeverity = ErrorSeverity.ERROR) { const enrichedContext = this.enrichContext(context); // Log to console in development if (this.environment === 'development') { console.error(`[ErrorLogger] ${severity.toUpperCase()}:`, error.message, { stack: error.stack, context: enrichedContext, }); } // Send to error tracking service if (this.enabled) { this.sendToService(error, enrichedContext, severity); } // Store locally for debugging this.storeLocally(error, enrichedContext, severity); } /** * Log an exception (wrapper for logError) */ captureException(error: Error, context?: ErrorContext) { this.logError(error, context, ErrorSeverity.ERROR); } /** * Log a message (non-error logging) */ captureMessage(message: string, context?: ErrorContext, severity: ErrorSeverity = ErrorSeverity.INFO) { const enrichedContext = this.enrichContext(context); if (this.environment === 'development') { console.log(`[ErrorLogger] ${severity.toUpperCase()}: ${message}`, enrichedContext); } if (this.enabled) { // TODO: Send to Sentry as message // Sentry.captureMessage(message, { // level: severity, // contexts: { custom: enrichedContext }, // }); } } /** * Add breadcrumb for debugging */ addBreadcrumb(message: string, category?: string, data?: Record) { if (this.environment === 'development') { console.log(`[ErrorLogger] Breadcrumb: ${category || 'default'} - ${message}`, data); } if (this.enabled) { // TODO: Add to Sentry // Sentry.addBreadcrumb({ // message, // category, // data, // timestamp: Date.now() / 1000, // }); } } /** * Set user context for error tracking */ setUser(user: { id: string; email?: string; name?: string }) { if (this.enabled) { // TODO: Set in Sentry // Sentry.setUser({ // id: user.id, // email: user.email, // username: user.name, // }); } } /** * Clear user context (e.g., on logout) */ clearUser() { if (this.enabled) { // TODO: Clear in Sentry // Sentry.setUser(null); } } /** * Set additional context tags */ setTag(key: string, value: string) { if (this.enabled) { // TODO: Set in Sentry // Sentry.setTag(key, value); } } /** * Enrich context with additional information */ private enrichContext(context?: ErrorContext): ErrorContext { return { ...context, url: typeof window !== 'undefined' ? window.location.href : undefined, userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined, timestamp: new Date().toISOString(), environment: this.environment, // Add app version if available appVersion: process.env.NEXT_PUBLIC_APP_VERSION, }; } /** * Send error to tracking service */ private sendToService(error: Error, context: ErrorContext, severity: ErrorSeverity) { // TODO: Implement Sentry integration // Sentry.captureException(error, { // level: severity, // contexts: { // custom: context, // }, // tags: { // errorBoundary: context.errorBoundary, // }, // }); } /** * Store error locally for debugging */ private storeLocally(error: Error, context: ErrorContext, severity: ErrorSeverity) { if (typeof window === 'undefined') return; try { const errorLog = { message: error.message, stack: error.stack, severity, context, timestamp: new Date().toISOString(), }; // Store in sessionStorage (limited to 10 most recent errors) const storedErrors = JSON.parse(sessionStorage.getItem('error_logs') || '[]'); storedErrors.push(errorLog); // Keep only last 10 errors if (storedErrors.length > 10) { storedErrors.shift(); } sessionStorage.setItem('error_logs', JSON.stringify(storedErrors)); } catch (e) { // Ignore storage errors console.error('Failed to store error locally:', e); } } /** * Get locally stored errors (for debugging) */ getLocalErrors() { if (typeof window === 'undefined') return []; try { return JSON.parse(sessionStorage.getItem('error_logs') || '[]'); } catch (e) { return []; } } /** * Clear locally stored errors */ clearLocalErrors() { if (typeof window !== 'undefined') { sessionStorage.removeItem('error_logs'); } } } // Export singleton instance export const errorLogger = new ErrorLogger(); // Initialize on import if (typeof window !== 'undefined') { errorLogger.init(); } export default errorLogger;