@aerocorp/cli
Version:
AeroCorp CLI 5.1.0 - Future-Proofed Enterprise Infrastructure with Live Preview, Tunneling & Advanced DevOps
202 lines ⢠8.35 kB
JavaScript
;
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