import log from 'loglevel'; /** * Application logger configuration and utilities */ // Define log levels for different parts of the application export enum LogLevel { TRACE = 0, DEBUG = 1, INFO = 2, WARN = 3, ERROR = 4, SILENT = 5, } // Log categories for better organization export enum LogCategory { PRESENTATION = 'presentation', THEME = 'theme', STORAGE = 'storage', UI = 'ui', SECURITY = 'security', PERFORMANCE = 'performance', GENERAL = 'general', } /** * Configure logging based on environment */ function configureLogger(): void { // Set default log level based on environment const isDevelopment = import.meta.env.DEV; const isProduction = import.meta.env.PROD; if (isDevelopment) { log.setLevel(LogLevel.DEBUG); } else if (isProduction) { log.setLevel(LogLevel.WARN); } else { log.setLevel(LogLevel.INFO); } // Add timestamp and category formatting const originalFactory = log.methodFactory; log.methodFactory = function (methodName, logLevel, loggerName) { const rawMethod = originalFactory(methodName, logLevel, loggerName); return function (category: LogCategory | string, message: string, ...args: LogData[]) { const timestamp = new Date().toISOString(); const formattedMessage = `[${timestamp}] [${methodName.toUpperCase()}] [${category}] ${message}`; if (args.length > 0) { rawMethod(formattedMessage, ...args); } else { rawMethod(formattedMessage); } }; }; // Apply the new factory log.setLevel(log.getLevel()); } /** * Valid log data types */ type LogData = string | number | boolean | null | undefined | Error | Record | unknown[]; /** * Logger interface for the application */ export interface Logger { trace(category: LogCategory, message: string, ...args: LogData[]): void; debug(category: LogCategory, message: string, ...args: LogData[]): void; info(category: LogCategory, message: string, ...args: LogData[]): void; warn(category: LogCategory, message: string, ...args: LogData[]): void; error(category: LogCategory, message: string, ...args: LogData[]): void; } /** * Create a logger instance with proper configuration */ function createLogger(): Logger { configureLogger(); return { trace: (category: LogCategory, message: string, ...args: LogData[]) => { log.trace(category, message, ...args); }, debug: (category: LogCategory, message: string, ...args: LogData[]) => { log.debug(category, message, ...args); }, info: (category: LogCategory, message: string, ...args: LogData[]) => { log.info(category, message, ...args); }, warn: (category: LogCategory, message: string, ...args: LogData[]) => { log.warn(category, message, ...args); }, error: (category: LogCategory, message: string, ...args: LogData[]) => { log.error(category, message, ...args); }, }; } // Export the configured logger instance export const logger = createLogger(); /** * Convenience functions for common logging scenarios */ export const loggers = { presentation: { info: (message: string, ...args: LogData[]) => logger.info(LogCategory.PRESENTATION, message, ...args), warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.PRESENTATION, message, ...args), error: (message: string, ...args: LogData[]) => logger.error(LogCategory.PRESENTATION, message, ...args), debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.PRESENTATION, message, ...args), }, theme: { info: (message: string, ...args: LogData[]) => logger.info(LogCategory.THEME, message, ...args), warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.THEME, message, ...args), error: (message: string, ...args: LogData[]) => logger.error(LogCategory.THEME, message, ...args), debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.THEME, message, ...args), }, storage: { info: (message: string, ...args: LogData[]) => logger.info(LogCategory.STORAGE, message, ...args), warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.STORAGE, message, ...args), error: (message: string, ...args: LogData[]) => logger.error(LogCategory.STORAGE, message, ...args), debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.STORAGE, message, ...args), }, ui: { info: (message: string, ...args: LogData[]) => logger.info(LogCategory.UI, message, ...args), warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.UI, message, ...args), error: (message: string, ...args: LogData[]) => logger.error(LogCategory.UI, message, ...args), debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.UI, message, ...args), }, security: { info: (message: string, ...args: LogData[]) => logger.info(LogCategory.SECURITY, message, ...args), warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.SECURITY, message, ...args), error: (message: string, ...args: LogData[]) => logger.error(LogCategory.SECURITY, message, ...args), debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.SECURITY, message, ...args), }, performance: { info: (message: string, ...args: LogData[]) => logger.info(LogCategory.PERFORMANCE, message, ...args), warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.PERFORMANCE, message, ...args), error: (message: string, ...args: LogData[]) => logger.error(LogCategory.PERFORMANCE, message, ...args), debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.PERFORMANCE, message, ...args), }, general: { info: (message: string, ...args: LogData[]) => logger.info(LogCategory.GENERAL, message, ...args), warn: (message: string, ...args: LogData[]) => logger.warn(LogCategory.GENERAL, message, ...args), error: (message: string, ...args: LogData[]) => logger.error(LogCategory.GENERAL, message, ...args), debug: (message: string, ...args: LogData[]) => logger.debug(LogCategory.GENERAL, message, ...args), }, }; /** * Performance timing utility */ export function createPerformanceTimer(operation: string) { const startTime = performance.now(); return { end: () => { const endTime = performance.now(); const duration = endTime - startTime; loggers.performance.info(`Operation '${operation}' completed in ${duration.toFixed(2)}ms`); return duration; } }; } /** * Error logging utility with stack trace */ export function logError(category: LogCategory, message: string, error?: Error | unknown, context?: Record) { if (error instanceof Error) { logger.error(category, `${message}: ${error.message}`, { stack: error.stack, context, }); } else { logger.error(category, message, { error, context }); } } /** * Development-only logging */ export function devLog(category: LogCategory, message: string, ...args: any[]) { if (import.meta.env.DEV) { logger.debug(category, `[DEV] ${message}`, ...args); } }