Spaces:
Sleeping
Sleeping
CarouselForge Developer
feat: Phase 15 complete — mobile responsiveness, monitoring, Telegram polish, UAT
d0ded63 | /** | |
| * Structured logging module for enhanced observability | |
| * Logs with severity levels, component tracking, and metrics | |
| */ | |
| type LogLevel = 'debug' | 'info' | 'warn' | 'error'; | |
| interface LogEntry { | |
| timestamp: string; | |
| level: LogLevel; | |
| component: string; | |
| message: string; | |
| duration?: number; // milliseconds | |
| error?: string; | |
| metadata?: Record<string, unknown>; | |
| } | |
| class Logger { | |
| private isProduction = typeof process !== 'undefined' && process.env.NODE_ENV === 'production'; | |
| /** | |
| * Log a message with timestamp and component context | |
| */ | |
| private log(level: LogLevel, component: string, message: string, metadata?: Record<string, unknown>) { | |
| const entry: LogEntry = { | |
| timestamp: new Date().toISOString(), | |
| level, | |
| component, | |
| message, | |
| metadata, | |
| }; | |
| const prefix = `[${component}]`; | |
| const formattedMessage = `${prefix} ${message}`; | |
| const logWithMetadata = (consoleFn: typeof console.error) => { | |
| if (metadata && Object.keys(metadata).length > 0) { | |
| consoleFn(formattedMessage, metadata); | |
| } else { | |
| consoleFn(formattedMessage); | |
| } | |
| }; | |
| switch (level) { | |
| case 'error': | |
| logWithMetadata(console.error); | |
| break; | |
| case 'warn': | |
| logWithMetadata(console.warn); | |
| break; | |
| case 'info': | |
| if (!this.isProduction) { | |
| logWithMetadata(console.log); | |
| } | |
| break; | |
| case 'debug': | |
| if (!this.isProduction) { | |
| logWithMetadata(console.debug); | |
| } | |
| break; | |
| } | |
| } | |
| /** | |
| * Log debug message (development only) | |
| */ | |
| debug(component: string, message: string, metadata?: Record<string, unknown>) { | |
| this.log('debug', component, message, metadata); | |
| } | |
| /** | |
| * Log info message | |
| */ | |
| info(component: string, message: string, metadata?: Record<string, unknown>) { | |
| this.log('info', component, message, metadata); | |
| } | |
| /** | |
| * Log warning message | |
| */ | |
| warn(component: string, message: string, metadata?: Record<string, unknown>) { | |
| this.log('warn', component, message, metadata); | |
| } | |
| /** | |
| * Log error with optional error object | |
| */ | |
| error(component: string, message: string, error?: Error | unknown, metadata?: Record<string, unknown>) { | |
| const errorMetadata = { | |
| ...metadata, | |
| ...(error instanceof Error && { | |
| errorMessage: error.message, | |
| errorStack: error.stack, | |
| }), | |
| }; | |
| this.log('error', component, message, errorMetadata); | |
| } | |
| /** | |
| * Measure performance of an async function and log duration | |
| */ | |
| async measureAsync<T>( | |
| component: string, | |
| operationName: string, | |
| fn: () => Promise<T>, | |
| ): Promise<T> { | |
| const start = performance.now(); | |
| try { | |
| const result = await fn(); | |
| const duration = performance.now() - start; | |
| this.debug(component, `${operationName} completed`, { duration: `${duration.toFixed(2)}ms` }); | |
| return result; | |
| } catch (error) { | |
| const duration = performance.now() - start; | |
| this.error(component, `${operationName} failed`, error, { duration: `${duration.toFixed(2)}ms` }); | |
| throw error; | |
| } | |
| } | |
| /** | |
| * Measure performance of a sync function and log duration | |
| */ | |
| measureSync<T>( | |
| component: string, | |
| operationName: string, | |
| fn: () => T, | |
| ): T { | |
| const start = performance.now(); | |
| try { | |
| const result = fn(); | |
| const duration = performance.now() - start; | |
| this.debug(component, `${operationName} completed`, { duration: `${duration.toFixed(2)}ms` }); | |
| return result; | |
| } catch (error) { | |
| const duration = performance.now() - start; | |
| this.error(component, `${operationName} failed`, error, { duration: `${duration.toFixed(2)}ms` }); | |
| throw error; | |
| } | |
| } | |
| } | |
| // Export singleton instance | |
| export const logger = new Logger(); | |
| /** | |
| * Helper for tracking async operation metrics | |
| */ | |
| export function createAsyncMetricsTracker(component: string, operationName: string) { | |
| const start = performance.now(); | |
| return { | |
| success: (metadata?: Record<string, unknown>) => { | |
| const duration = performance.now() - start; | |
| logger.info(component, `${operationName} succeeded`, { duration: `${duration.toFixed(2)}ms`, ...metadata }); | |
| }, | |
| error: (error: Error | unknown, metadata?: Record<string, unknown>) => { | |
| const duration = performance.now() - start; | |
| logger.error(component, `${operationName} failed`, error, { duration: `${duration.toFixed(2)}ms`, ...metadata }); | |
| }, | |
| }; | |
| } | |