UNPKG

forge-deploy-cli

Version:

Professional CLI for local deployments with automatic subdomain routing, SSL certificates, and infrastructure management

215 lines 10.6 kB
"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; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.logsCommand = void 0; const commander_1 = require("commander"); const chalk_1 = __importDefault(require("chalk")); const api_1 = require("../services/api"); const config_1 = require("../services/config"); const localDeployment_1 = require("../services/localDeployment"); const child_process_1 = require("child_process"); const path_1 = __importDefault(require("path")); exports.logsCommand = new commander_1.Command('logs') .description('View application logs') .argument('[deployment-id]', 'Deployment ID (optional, defaults to current project)') .option('-f, --follow', 'Follow log output') .option('-t, --tail <lines>', 'Number of lines to show from the end', '100') .option('--error', 'Show only error logs') .option('--access', 'Show only access logs') .option('--local', 'Show only local PM2 logs') .option('--remote', 'Show only remote API logs') .action(async (deploymentId, options) => { try { const configService = new config_1.ConfigService(); const config = await configService.loadProjectConfig(); if (!config) { console.log(chalk_1.default.red('Error: Not in a Forge project directory')); console.log('Run "forge init" to initialize a project'); process.exit(1); } const globalConfig = await configService.loadGlobalConfig(); if (!globalConfig?.apiKey) { console.log(chalk_1.default.red('Error: Not authenticated')); console.log('Run "forge login" to authenticate'); process.exit(1); } console.log(chalk_1.default.blue('Fetching logs...')); const api = new api_1.ForgeApiService(); api.setApiKey(globalConfig.apiKey); const logOptions = { tail: parseInt(options.tail), follow: options.follow, type: options.error ? 'error' : options.access ? 'access' : 'all' }; if (options.follow) { console.log(chalk_1.default.yellow('Following logs (Press Ctrl+C to stop)...')); console.log(chalk_1.default.gray('---')); // Simulate log streaming (in a real implementation, this would be a WebSocket or SSE connection) const interval = setInterval(async () => { try { if (config.deploymentId) { const response = await api.getDeploymentLogs(config.deploymentId); const logs = response.data?.logs || []; logs.slice(-parseInt(options.tail)).forEach((log) => { const timestamp = new Date(log.timestamp).toISOString(); const level = log.level === 'error' ? chalk_1.default.red(log.level) : log.level === 'warn' ? chalk_1.default.yellow(log.level) : chalk_1.default.white(log.level); console.log(`${chalk_1.default.gray(timestamp)} ${level} ${log.message}`); }); } } catch (error) { console.log(chalk_1.default.red(`Error fetching logs: ${error}`)); clearInterval(interval); } }, 2000); process.on('SIGINT', () => { clearInterval(interval); console.log(chalk_1.default.yellow('\nStopped following logs')); process.exit(0); }); } else { if (!config.deploymentId) { console.log(chalk_1.default.yellow('No deployment found. Deploy your app first with "forge deploy"')); return; } // Show both local PM2 logs and remote API logs if (!options.remote) { console.log(chalk_1.default.blue('📁 Local PM2 Logs:')); await showLocalLogs(config.deploymentId, options); } if (!options.local) { console.log(chalk_1.default.blue('🌐 Remote API Logs:')); try { const response = await api.getDeploymentLogs(config.deploymentId); const logs = response.data?.logs || []; if (logs.length === 0) { console.log(chalk_1.default.yellow('No remote logs found')); } else { const filteredLogs = logs.slice(-parseInt(options.tail)); console.log(chalk_1.default.gray('---')); filteredLogs.forEach((log) => { const timestamp = new Date(log.timestamp).toISOString(); const level = log.level === 'error' ? chalk_1.default.red(log.level) : log.level === 'warn' ? chalk_1.default.yellow(log.level) : chalk_1.default.white(log.level); console.log(`${chalk_1.default.gray(timestamp)} ${level} ${log.message}`); }); console.log(chalk_1.default.gray('---')); console.log(chalk_1.default.green(`Showing last ${filteredLogs.length} remote log entries`)); } } catch (apiError) { console.log(chalk_1.default.yellow(`⚠️ Remote logs unavailable: ${apiError}`)); console.log(chalk_1.default.gray('API might be down or deployment not found remotely')); if (options.local) { console.log(chalk_1.default.gray('Showing local logs only')); } } } } } catch (error) { console.log(chalk_1.default.red(`Error: ${error}`)); process.exit(1); } }); async function showLocalLogs(deploymentId, options) { try { // Check if deployment exists locally const deployment = await localDeployment_1.LocalDeploymentManager.getDeployment(deploymentId); if (!deployment) { console.log(chalk_1.default.yellow('Local deployment not found')); return; } const appName = `forge-${deploymentId}`; const logTail = options.tail || '100'; try { // Try to get PM2 logs console.log(chalk_1.default.gray(`PM2 Process: ${appName}`)); if (options.error) { // Show error logs only const errorLogs = (0, child_process_1.execSync)(`pm2 logs ${appName} --err --lines ${logTail}`, { encoding: 'utf8' }); console.log(errorLogs); } else { // Show all logs const allLogs = (0, child_process_1.execSync)(`pm2 logs ${appName} --lines ${logTail}`, { encoding: 'utf8' }); console.log(allLogs); } } catch (pm2Error) { // PM2 logs failed, try to show log files directly console.log(chalk_1.default.yellow('PM2 logs not available, checking log files...')); const logDir = path_1.default.join(process.cwd(), 'logs'); const errorFile = path_1.default.join(logDir, `${deploymentId}-error.log`); const outFile = path_1.default.join(logDir, `${deploymentId}-out.log`); const combinedFile = path_1.default.join(logDir, `${deploymentId}-combined.log`); const fs = await Promise.resolve().then(() => __importStar(require('fs-extra'))); if (await fs.pathExists(combinedFile)) { console.log(chalk_1.default.gray(`Reading log file: ${combinedFile}`)); const logs = await fs.readFile(combinedFile, 'utf8'); const lines = logs.split('\n').slice(-parseInt(logTail)); console.log(lines.join('\n')); } else if (await fs.pathExists(outFile)) { console.log(chalk_1.default.gray(`Reading output log: ${outFile}`)); const logs = await fs.readFile(outFile, 'utf8'); const lines = logs.split('\n').slice(-parseInt(logTail)); console.log(lines.join('\n')); if (await fs.pathExists(errorFile)) { console.log(chalk_1.default.red('\nError Logs:')); const errorLogs = await fs.readFile(errorFile, 'utf8'); const errorLines = errorLogs.split('\n').slice(-parseInt(logTail)); console.log(errorLines.join('\n')); } } else { console.log(chalk_1.default.yellow('No local log files found')); console.log(chalk_1.default.gray(`Expected log files in: ${logDir}`)); } } } catch (error) { console.log(chalk_1.default.red(`Error reading local logs: ${error}`)); } } //# sourceMappingURL=logs.js.map