UNPKG

@aerocorp/cli

Version:

AeroCorp CLI 5.1.0 - Future-Proofed Enterprise Infrastructure with Live Preview, Tunneling & Advanced DevOps

202 lines • 8.35 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LogService = void 0; const axios_1 = __importDefault(require("axios")); const chalk_1 = __importDefault(require("chalk")); const ora_1 = __importDefault(require("ora")); const auth_1 = require("./auth"); class LogService { constructor() { this.authService = new auth_1.AuthService(); } async getLogs(appName, options) { if (!this.authService.isAuthenticated()) { throw new Error('Not authenticated. Run "aerocorp login" first.'); } const spinner = (0, ora_1.default)(`Fetching logs for ${appName}...`).start(); try { const coolifyUrl = this.authService.getCoolifyUrl(); const headers = this.authService.getAuthHeaders(); // Find the application const app = await this.findApplication(coolifyUrl, headers, appName); if (!app) { spinner.fail(`Application '${appName}' not found`); throw new Error(`Application '${appName}' not found`); } // Get logs const logsResponse = await axios_1.default.get(`${coolifyUrl}/api/v1/applications/${app.id}/logs`, { headers, params: { lines: options.tail || 100, follow: options.follow || false } }); spinner.succeed(`Logs fetched for ${appName}`); // Display logs this.displayLogs(appName, logsResponse.data, options); // If follow mode, set up streaming if (options.follow) { await this.followLogs(coolifyUrl, headers, app.id, appName); } } catch (error) { spinner.fail(`Failed to fetch logs for ${appName}`); if (error.response?.status === 404) { throw new Error(`Application '${appName}' not found or no logs available`); } else { throw new Error(`API Error: ${error.response?.data?.message || error.message}`); } } } async findApplication(coolifyUrl, headers, appName) { try { // Get all projects const projectsResponse = await axios_1.default.get(`${coolifyUrl}/api/v1/projects`, { headers }); const projects = projectsResponse.data; // Search for application in all projects for (const project of projects) { try { const appsResponse = await axios_1.default.get(`${coolifyUrl}/api/v1/projects/${project.id}/applications`, { headers }); const app = appsResponse.data.find((app) => app.name === appName || app.name.includes(appName)); if (app) { return app; } } catch (error) { // Continue searching in other projects continue; } } return null; } catch (error) { throw new Error(`Failed to search for application: ${error.message}`); } } displayLogs(appName, logs, options) { console.log(chalk_1.default.cyan(`\nšŸ“‹ Logs for ${appName}`)); console.log(chalk_1.default.cyan('='.repeat(50))); if (!logs || (Array.isArray(logs) && logs.length === 0)) { console.log(chalk_1.default.yellow('⚠ No logs available')); return; } // Handle different log formats let logEntries = []; if (typeof logs === 'string') { logEntries = logs.split('\n').filter(line => line.trim()); } else if (Array.isArray(logs)) { logEntries = logs; } else if (logs.logs) { logEntries = Array.isArray(logs.logs) ? logs.logs : logs.logs.split('\n'); } logEntries.forEach((logEntry, index) => { let logLine; let timestamp = ''; let level = ''; let message = ''; if (typeof logEntry === 'string') { logLine = logEntry; // Try to parse timestamp and level const timestampMatch = logLine.match(/^(\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}:\d{2})/); if (timestampMatch) { timestamp = timestampMatch[1]; logLine = logLine.substring(timestampMatch[0].length).trim(); } const levelMatch = logLine.match(/^(ERROR|WARN|INFO|DEBUG|TRACE)/i); if (levelMatch) { level = levelMatch[1].toUpperCase(); message = logLine.substring(levelMatch[0].length).trim(); } else { message = logLine; } } else { timestamp = logEntry.timestamp || logEntry.time || ''; level = logEntry.level || logEntry.severity || ''; message = logEntry.message || logEntry.msg || JSON.stringify(logEntry); } // Format output let output = ''; if (timestamp) { output += chalk_1.default.gray(`[${timestamp}] `); } if (level) { const levelColor = this.getLevelColor(level); output += chalk_1.default[levelColor](`${level.padEnd(5)} `); } output += message; console.log(output); }); console.log(chalk_1.default.cyan(`\nšŸ“Š Showing ${logEntries.length} log entries`)); } getLevelColor(level) { switch (level.toUpperCase()) { case 'ERROR': return 'red'; case 'WARN': case 'WARNING': return 'yellow'; case 'INFO': return 'blue'; case 'DEBUG': return 'magenta'; case 'TRACE': return 'gray'; default: return 'white'; } } async followLogs(coolifyUrl, headers, appId, appName) { console.log(chalk_1.default.blue(`\nšŸ‘ļø Following logs for ${appName} (Press Ctrl+C to stop)...`)); let lastLogCount = 0; const followInterval = setInterval(async () => { try { const logsResponse = await axios_1.default.get(`${coolifyUrl}/api/v1/applications/${appId}/logs`, { headers, params: { lines: 50 } }); let logEntries = []; const logs = logsResponse.data; if (typeof logs === 'string') { logEntries = logs.split('\n').filter(line => line.trim()); } else if (Array.isArray(logs)) { logEntries = logs; } else if (logs.logs) { logEntries = Array.isArray(logs.logs) ? logs.logs : logs.logs.split('\n'); } // Only show new logs if (logEntries.length > lastLogCount) { const newLogs = logEntries.slice(lastLogCount); newLogs.forEach(logEntry => { let message = typeof logEntry === 'string' ? logEntry : logEntry.message || JSON.stringify(logEntry); console.log(chalk_1.default.gray(`[${new Date().toISOString()}] `) + message); }); lastLogCount = logEntries.length; } } catch (error) { console.error(chalk_1.default.red(`Error fetching logs: ${error.message}`)); } }, 2000); // Poll every 2 seconds // Handle Ctrl+C process.on('SIGINT', () => { clearInterval(followInterval); console.log(chalk_1.default.yellow('\nšŸ‘‹ Stopped following logs')); process.exit(0); }); } } exports.LogService = LogService; //# sourceMappingURL=log.js.map