"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.LogSourceManager = void 0; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const zlib = __importStar(require("zlib")); const child_process_1 = require("child_process"); class LogSourceManager { configManager; sources = new Map(); constructor(configManager) { this.configManager = configManager; this.initializeSources(); } initializeSources() { const configSources = this.configManager.getSources(); for (const source of configSources) { this.addSource(source); } } addSource(sourcePath) { if (sourcePath.includes('*')) { const resolvedPaths = this.resolveGlob(sourcePath); for (const rp of resolvedPaths) { this.addSingleSource(rp); } } else { this.addSingleSource(sourcePath); } this.configManager.updateSources(Array.from(this.sources.keys())); } addSingleSource(sourcePath) { const resolved = path.resolve(sourcePath); const type = this.detectType(resolved); let size = 0; let lastModified = null; let exists = false; try { const stats = fs.statSync(resolved); size = stats.size; lastModified = stats.mtime.toISOString(); exists = true; } catch { // File doesn't exist yet } this.sources.set(resolved, { path: resolved, displayName: path.basename(resolved), type, size, lastModified, exists, }); } removeSource(sourcePath) { const resolved = path.resolve(sourcePath); this.sources.delete(resolved); this.configManager.updateSources(Array.from(this.sources.keys())); } getSources() { for (const [key, source] of this.sources) { try { const stats = fs.statSync(key); source.size = stats.size; source.lastModified = stats.mtime.toISOString(); source.exists = true; } catch { source.exists = false; } } return Array.from(this.sources.values()); } detectType(filePath) { const ext = path.extname(filePath).toLowerCase(); switch (ext) { case '.gz': case '.gzip': return 'gzip'; case '.bz2': case '.bzip2': return 'bzip2'; case '.xz': return 'xz'; case '.zst': case '.zstd': return 'zstd'; default: return 'text'; } } async readLog(sourcePath) { const resolved = path.resolve(sourcePath); const source = this.sources.get(resolved); if (!source) throw new Error(`Source not found: ${sourcePath}`); const config = this.configManager.getConfig(); const content = this.readFileContent(resolved, source.type); const lines = content.split('\n'); const maxLines = config.maxLines; const startIndex = lines.length > maxLines ? lines.length - maxLines : 0; const entries = []; for (let i = startIndex; i < lines.length; i++) { const line = lines[i]; if (line.trim() === '') continue; entries.push({ line, lineNumber: i + 1, source: resolved, timestamp: this.extractTimestamp(line, config.timestampRegex), level: this.extractLevel(line), }); } return entries; } async readAllLogs() { const allEntries = []; for (const [sourcePath] of this.sources) { try { const entries = await this.readLog(sourcePath); allEntries.push(...entries); } catch (err) { allEntries.push({ line: `[ERROR] Could not read ${sourcePath}: ${err.message}`, lineNumber: 0, source: sourcePath, timestamp: new Date().toISOString(), level: 'ERROR', }); } } allEntries.sort((a, b) => { if (a.timestamp && b.timestamp) return a.timestamp.localeCompare(b.timestamp); return 0; }); return allEntries; } readFileContent(filePath, type) { switch (type) { case 'gzip': return this.readGzip(filePath); case 'bzip2': return this.readBzip2(filePath); case 'xz': return this.readXz(filePath); case 'zstd': return this.readZstd(filePath); default: return fs.readFileSync(filePath, 'utf-8'); } } readGzip(filePath) { const compressed = fs.readFileSync(filePath); return zlib.gunzipSync(compressed).toString('utf-8'); } readBzip2(filePath) { try { return (0, child_process_1.execSync)(`bzcat "${filePath}"`, { maxBuffer: 100 * 1024 * 1024 }).toString('utf-8'); } catch { throw new Error('Cannot decompress bzip2. Make sure bzip2 is installed.'); } } readXz(filePath) { try { return (0, child_process_1.execSync)(`xzcat "${filePath}"`, { maxBuffer: 100 * 1024 * 1024 }).toString('utf-8'); } catch { throw new Error('Cannot decompress xz. Make sure xz-utils is installed.'); } } readZstd(filePath) { try { return (0, child_process_1.execSync)(`zstdcat "${filePath}"`, { maxBuffer: 100 * 1024 * 1024 }).toString('utf-8'); } catch { throw new Error('Cannot decompress zstd. Make sure zstd is installed.'); } } extractTimestamp(line, customRegex) { const patterns = [ /(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?)/, /^([A-Z][a-z]{2}\s+\d{1,2}\s+\d{2}:\d{2}:\d{2})/, /\[(\d{2}\/[A-Z][a-z]{2}\/\d{4}:\d{2}:\d{2}:\d{2}\s[+-]\d{4})\]/, /(\d{4}\/\d{2}\/\d{2}\s+\d{2}:\d{2}:\d{2})/, ]; if (customRegex) { try { const match = line.match(new RegExp(customRegex)); if (match) return match[1] || match[0]; } catch { /* skip */ } } for (const pattern of patterns) { const match = line.match(pattern); if (match) return match[1]; } return null; } extractLevel(line) { const upper = line.toUpperCase(); const levels = ['FATAL', 'ERROR', 'WARN', 'WARNING', 'INFO', 'DEBUG', 'TRACE', 'VERBOSE']; for (const level of levels) { if (new RegExp(`\\b${level}\\b`).test(upper)) { return level === 'WARNING' ? 'WARN' : level; } } return null; } resolveGlob(pattern) { const dir = path.dirname(pattern); const filePattern = path.basename(pattern); const results = []; try { const files = fs.readdirSync(dir); const regex = new RegExp('^' + filePattern.replace(/\./g, '\\.').replace(/\*/g, '.*').replace(/\?/g, '.') + '$'); for (const file of files) { if (regex.test(file)) { const fullPath = path.join(dir, file); try { if (fs.statSync(fullPath).isFile()) results.push(fullPath); } catch { /* skip */ } } } } catch { /* dir doesn't exist */ } return results; } async getFileStats(sourcePath) { const resolved = path.resolve(sourcePath); try { const stats = fs.statSync(resolved); const source = this.sources.get(resolved); const content = this.readFileContent(resolved, source?.type || 'text'); return { size: stats.size, lastModified: stats.mtime.toISOString(), lineCount: content.split('\n').length, type: source?.type || 'text', }; } catch { return null; } } } exports.LogSourceManager = LogSourceManager; //# sourceMappingURL=logSourceManager.js.map