UNPKG

@200systems/mf-logger

Version:

Structured logging with multiple outputs and performance timing for TypeScript applications

222 lines 7.33 kB
import { createFileHandler, BrowserStorageHandler } from './file-handlers.js'; import { ENV } from './environment.js'; export class BaseOutput { } export class ConsoleOutput extends BaseOutput { write(entry, formatted) { const method = entry.level === 'error' ? 'error' : entry.level === 'warn' ? 'warn' : 'log'; console[method](formatted); } } export class FileOutput extends BaseOutput { filePath; maxSize; maxFiles; fileHandler; initPromise = null; constructor(filePath, maxSize = 10 * 1024 * 1024, // 10MB maxFiles = 5) { super(); this.filePath = filePath; this.maxSize = maxSize; this.maxFiles = maxFiles; this.fileHandler = createFileHandler({ filePath: this.filePath, maxSize: this.maxSize, maxFiles: this.maxFiles }); } async write(entry, formatted) { // Ensure initialization happens only once if (!this.initPromise) { this.initPromise = this.fileHandler.initialize(); } try { await this.initPromise; await this.fileHandler.write(formatted + '\n'); } catch (error) { console.error('Failed to write to file output:', error); } } // Utility method for browser storage handler retrieveLogs() { if (this.fileHandler instanceof BrowserStorageHandler) { return this.fileHandler.retrieveLogs(); } return null; } clearLogs() { if (this.fileHandler instanceof BrowserStorageHandler) { this.fileHandler.clearLogs(); } } } export class CustomOutput extends BaseOutput { handler; constructor(handler) { super(); this.handler = handler; } async write(entry) { try { await this.handler(entry); } catch (error) { console.error('Custom log handler failed:', error); } } } // Browser-specific output for structured logging export class BrowserConsoleOutput extends BaseOutput { write(entry, formatted) { const styles = this.getConsoleStyles(entry.level); if (ENV.isBrowser && console.groupCollapsed) { console.groupCollapsed(`%c${entry.level.toUpperCase()}%c ${entry.message}`, styles.level, styles.message); if (entry.metadata) { console.log('Metadata:', entry.metadata); } if (entry.error) { console.error('Error:', entry.error); } if (entry.performance) { console.log('Performance:', entry.performance); } console.groupEnd(); } else { // Fallback to regular console const method = entry.level === 'error' ? 'error' : entry.level === 'warn' ? 'warn' : 'log'; console[method](formatted); } } getConsoleStyles(level) { const baseStyle = 'padding: 2px 4px; border-radius: 2px; font-weight: bold;'; switch (level) { case 'error': return { level: `${baseStyle} background: #ff4444; color: white;`, message: 'color: #ff4444;' }; case 'warn': return { level: `${baseStyle} background: #ffaa00; color: white;`, message: 'color: #ffaa00;' }; case 'info': return { level: `${baseStyle} background: #0088ff; color: white;`, message: 'color: #0088ff;' }; case 'debug': return { level: `${baseStyle} background: #888888; color: white;`, message: 'color: #888888;' }; default: return { level: baseStyle, message: '' }; } } } // Remote logging output for browser environments export class RemoteOutput extends BaseOutput { endpoint; batchSize; flushInterval; constructor(endpoint, batchSize = 10, flushInterval = 5000 // 5 seconds ) { super(); this.endpoint = endpoint; this.batchSize = batchSize; this.flushInterval = flushInterval; this.startBatchProcessor(); } batch = []; batchTimer = null; async write(entry) { this.batch.push(entry); if (this.batch.length >= this.batchSize) { await this.flush(); } } startBatchProcessor() { this.batchTimer = setInterval(() => { if (this.batch.length > 0) { this.flush().catch(error => { console.error('Failed to flush log batch:', error); }); } }, this.flushInterval); } async flush() { if (this.batch.length === 0) return; const logsToSend = this.batch.splice(0); try { const response = await fetch(this.endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ logs: logsToSend }), }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } } catch (error) { console.error('Failed to send logs to remote endpoint:', error); // Re-add logs to batch for retry (optional) this.batch.unshift(...logsToSend); } } // Cleanup method destroy() { if (this.batchTimer) { clearInterval(this.batchTimer); this.batchTimer = null; } if (this.batch.length > 0) { this.flush().catch(console.error); } } } export function createOutput(config) { switch (config.type) { case 'console': { const options = config.options; // Use enhanced browser console in browser environments if (ENV.isBrowser && options?.enhanced !== false) { return new BrowserConsoleOutput(); } return new ConsoleOutput(); } case 'file': { const options = config.options; if (!options?.filePath) { throw new Error('File output requires filePath option'); } return new FileOutput(options.filePath, options.maxSize, options.maxFiles); } case 'custom': { const options = config.options; if (!options?.customHandler) { throw new Error('Custom output requires customHandler option'); } return new CustomOutput(options.customHandler); } case 'remote': { const options = config.options; if (!options?.endpoint) { throw new Error('Remote output requires endpoint option'); } return new RemoteOutput(options.endpoint, options.batchSize, options.flushInterval); } default: throw new Error(`Unknown output type: ${config.type}`); } } //# sourceMappingURL=outputs.js.map