An in-browser wisp.place site explorer
at main 119 lines 3.0 kB view raw
1/** 2 * Universal logging utility with levels and context support 3 */ 4 5export enum LogLevel { 6 DEBUG = 0, 7 INFO = 1, 8 WARN = 2, 9 ERROR = 3, 10} 11 12export interface LoggerOptions { 13 level?: LogLevel; 14 prefix?: string; 15 json?: boolean; 16} 17 18export class Logger { 19 private level: LogLevel; 20 private prefix: string; 21 private json: boolean; 22 23 constructor(options: LoggerOptions = {}) { 24 this.level = options.level ?? LogLevel.INFO; 25 this.prefix = options.prefix ?? ''; 26 this.json = options.json ?? false; 27 28 // Browser: check VITE_DEBUG flag 29 if (typeof import.meta !== 'undefined' && import.meta.env?.VITE_DEBUG === 'true' && this.level > LogLevel.DEBUG) { 30 this.level = LogLevel.DEBUG; 31 } 32 } 33 34 private shouldLog(level: LogLevel): boolean { 35 return level >= this.level; 36 } 37 38 private formatMessage(level: string, message: string, meta?: unknown): string { 39 const timestamp = new Date().toISOString(); 40 const prefix = this.prefix ? `[${this.prefix}] ` : ''; 41 42 if (this.json) { 43 return JSON.stringify({ 44 timestamp, 45 level, 46 prefix: this.prefix || undefined, 47 message, 48 ...(meta && typeof meta === 'object' ? meta : { value: meta }), 49 }); 50 } 51 52 const metaStr = meta ? ` ${JSON.stringify(meta)}` : ''; 53 return `${timestamp} ${prefix}${level}: ${message}${metaStr}`; 54 } 55 56 debug(message: string, meta?: unknown): void { 57 if (this.shouldLog(LogLevel.DEBUG)) { 58 const formatted = this.formatMessage('DEBUG', message, meta); 59 console.debug(formatted); 60 } 61 } 62 63 info(message: string, meta?: unknown): void { 64 if (this.shouldLog(LogLevel.INFO)) { 65 const formatted = this.formatMessage('INFO', message, meta); 66 console.log(formatted); 67 } 68 } 69 70 warn(message: string, meta?: unknown): void { 71 if (this.shouldLog(LogLevel.WARN)) { 72 const formatted = this.formatMessage('WARN', message, meta); 73 console.warn(formatted); 74 } 75 } 76 77 error(message: string, meta?: unknown): void { 78 if (this.shouldLog(LogLevel.ERROR)) { 79 const formatted = this.formatMessage('ERROR', message, meta); 80 console.error(formatted); 81 } 82 } 83 84 child(prefix: string): Logger { 85 return new Logger({ 86 level: this.level, 87 prefix: this.prefix ? `${this.prefix}:${prefix}` : prefix, 88 json: this.json, 89 }); 90 } 91 92 setLevel(level: LogLevel): void { 93 this.level = level; 94 } 95} 96 97/** 98 * Create a logger instance with default settings 99 */ 100export function createLogger(options?: LoggerOptions): Logger { 101 // Universal environment detection 102 const isBrowser = typeof import.meta !== 'undefined'; 103 const isDev = isBrowser 104 ? (import.meta.env.DEV ?? true) 105 : (process.env.NODE_ENV !== 'production'); 106 107 const defaultLevel = isDev ? LogLevel.DEBUG : LogLevel.INFO; 108 109 return new Logger({ 110 level: options?.level ?? defaultLevel, 111 prefix: options?.prefix, 112 json: options?.json ?? !isDev, 113 }); 114} 115 116/** 117 * Default logger instance 118 */ 119export const logger = createLogger({ prefix: 'wisp' });