/**
* Custom Logger System for Web UI
*
* Lightweight, structured logging system for browser environments.
* Uses console methods appropriate for client-side logging.
*/
/**
* Log levels in order of severity
*/
export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
/**
* Structured log entry
*/
export interface LogEntry {
timestamp: string
level: LogLevel
module: string
message: string
context?: Record<string, unknown>
}
/**
* Logger interface
*/
export interface Logger {
debug(message: string, context?: Record<string, unknown>): void
info(message: string, context?: Record<string, unknown>): void
warn(message: string, context?: Record<string, unknown>): void
error(message: string, context?: Record<string, unknown>): void
}
/**
* Logger configuration options
*/
export interface LoggerOptions {
/**
* Minimum log level to output
* @default 'info'
*/
minLevel?: LogLevel
/**
* Custom output function
* @default Outputs to appropriate console method
*/
output?: (entry: LogEntry) => void
}
/**
* Log level priority for filtering
*/
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
debug: 0,
info: 1,
warn: 2,
error: 3,
}
/**
* Format a log entry for output
*/
function formatLogEntry(entry: LogEntry): string {
const level = entry.level.toUpperCase()
const contextStr = entry.context ? ` ${JSON.stringify(entry.context)}` : ''
return `[${entry.timestamp}] [${level}] [${entry.module}] ${entry.message}${contextStr}`
}
/**
* Default output function (uses appropriate console method)
*/
function defaultOutput(entry: LogEntry): void {
const message = formatLogEntry(entry)
// Use the appropriate console method for the log level
switch (entry.level) {
case 'debug':
console.debug(message)
break
case 'info':
console.info(message)
break
case 'warn':
console.warn(message)
break
case 'error':
console.error(message)
break
}
}
/**
* Create a logger instance for a specific module
*
* @param module - Module name (e.g., 'socket', 'api', 'ui')
* @param options - Logger configuration options
* @returns Logger instance
*
* @example
* ```typescript
* const logger = createLogger('socket')
* logger.info('Connected to WebSocket', { port: 3002 })
* // Output: [2025-12-02T10:30:45.123Z] [INFO] [socket] Connected to WebSocket {"port":3002}
* ```
*/
export function createLogger(module: string, options?: LoggerOptions): Logger {
const minLevel = options?.minLevel ?? 'info'
const output = options?.output ?? defaultOutput
const minLevelPriority = LOG_LEVEL_PRIORITY[minLevel]
/**
* Internal log function
*/
function log(level: LogLevel, message: string, context?: Record<string, unknown>): void {
// Filter by minimum level
if (LOG_LEVEL_PRIORITY[level] < minLevelPriority) {
return
}
const entry: LogEntry = {
timestamp: new Date().toISOString(),
level,
module,
message,
context,
}
output(entry)
}
return {
debug: (message: string, context?: Record<string, unknown>) => log('debug', message, context),
info: (message: string, context?: Record<string, unknown>) => log('info', message, context),
warn: (message: string, context?: Record<string, unknown>) => log('warn', message, context),
error: (message: string, context?: Record<string, unknown>) => log('error', message, context),
}
}