From 33dd90af046716d4a277c97b11273f42d0620dab Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Fri, 17 Jan 2025 14:44:24 -0500 Subject: [PATCH] feat: better pm2 calls, log lines --- api/src/consts.ts | 5 +-- api/src/unraid-api/cli/cli.module.ts | 4 ++- api/src/unraid-api/cli/logs.command.ts | 37 +++++++++++++++++++++++ api/src/unraid-api/cli/restart.command.ts | 26 +++++++++++++--- api/src/unraid-api/cli/start.command.ts | 31 +++++++++---------- 5 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 api/src/unraid-api/cli/logs.command.ts diff --git a/api/src/consts.ts b/api/src/consts.ts index fdd563269..96a41c69a 100644 --- a/api/src/consts.ts +++ b/api/src/consts.ts @@ -1,5 +1,5 @@ import { PORT } from '@app/environment'; -import { type JSONWebKeySet } from 'jose'; +import type { JSONWebKeySet } from 'jose'; import { join } from 'path'; export const getInternalApiAddress = (isHttp = true, nginxPort = 80) => { @@ -81,4 +81,5 @@ export const KEYSERVER_VALIDATION_ENDPOINT = /** Set the max retries for the GraphQL Client */ export const MAX_RETRIES_FOR_LINEAR_BACKOFF = 100; -export const PM2_PATH = join(import.meta.dirname, '../../', 'node_modules', '.bin', 'pm2'); \ No newline at end of file +export const PM2_PATH = join(import.meta.dirname, '../../', 'node_modules', '.bin', 'pm2'); +export const ECOSYSTEM_PATH = join(import.meta.dirname, '../../', 'ecosystem.config.json'); \ No newline at end of file diff --git a/api/src/unraid-api/cli/cli.module.ts b/api/src/unraid-api/cli/cli.module.ts index 2a7eb3ed7..bd1809391 100644 --- a/api/src/unraid-api/cli/cli.module.ts +++ b/api/src/unraid-api/cli/cli.module.ts @@ -10,6 +10,7 @@ import { SwitchEnvCommand } from '@app/unraid-api/cli/switch-env.command'; import { VersionCommand } from '@app/unraid-api/cli/version.command'; import { StatusCommand } from '@app/unraid-api/cli/status.command'; import { ValidateTokenCommand } from '@app/unraid-api/cli/validate-token.command'; +import { LogsCommand } from '@app/unraid-api/cli/logs.command'; @Module({ providers: [ @@ -22,7 +23,8 @@ import { ValidateTokenCommand } from '@app/unraid-api/cli/validate-token.command SwitchEnvCommand, VersionCommand, StatusCommand, - ValidateTokenCommand + ValidateTokenCommand, + LogsCommand ], }) export class CliModule {} diff --git a/api/src/unraid-api/cli/logs.command.ts b/api/src/unraid-api/cli/logs.command.ts new file mode 100644 index 000000000..356463aae --- /dev/null +++ b/api/src/unraid-api/cli/logs.command.ts @@ -0,0 +1,37 @@ +import { execa } from 'execa'; +import { Command, CommandRunner, Option } from 'nest-commander'; + +import { ECOSYSTEM_PATH, PM2_PATH } from '@app/consts'; +import { LogService } from '@app/unraid-api/cli/log.service'; + +interface LogsOptions { + lines: number +} + +@Command({ name: 'logs' }) +export class LogsCommand extends CommandRunner { + constructor(private readonly logger: LogService) { + super(); + } + + @Option({ flags: '-l, --lines', description: 'Number of lines to tail'}) + parseLines(input: string): number + { + return isNaN(parseInt(input)) ? 100 : parseInt(input) + } + + async run(passedParams: string[], options?: LogsOptions): Promise { + const lines = options?.lines ?? 100; + const subprocess = execa(PM2_PATH, ['logs', ECOSYSTEM_PATH, '--lines', lines.toString()]); + + subprocess.stdout?.on('data', (data) => { + this.logger.log(data.toString()); + }); + + subprocess.stderr?.on('data', (data) => { + this.logger.error(data.toString()); + }); + + await subprocess; + } +} diff --git a/api/src/unraid-api/cli/restart.command.ts b/api/src/unraid-api/cli/restart.command.ts index 290dada60..c1631157d 100644 --- a/api/src/unraid-api/cli/restart.command.ts +++ b/api/src/unraid-api/cli/restart.command.ts @@ -1,22 +1,38 @@ -import { PM2_PATH } from '@app/consts'; import { execSync } from 'child_process'; -import { Command, CommandRunner } from 'nest-commander'; import { join } from 'path'; + + +import { Command, CommandRunner } from 'nest-commander'; + + + +import { ECOSYSTEM_PATH, PM2_PATH } from '@app/consts'; + + + + + /** * Stop a running API process and then start it again. */ @Command({ name: 'restart', description: 'Restart / Start the Unraid API'}) export class RestartCommand extends CommandRunner { async run(_): Promise { + console.log( + 'Dirname is ', + import.meta.dirname, + ' command is ', + `${PM2_PATH} restart ${ECOSYSTEM_PATH} --update-env` + ); execSync( - `${PM2_PATH} restart ${join(import.meta.dirname, '../../', 'ecosystem.config.json')} --update-env`, + `${PM2_PATH} restart ${ECOSYSTEM_PATH} --update-env`, { env: process.env, - stdio: 'inherit', + stdio: 'pipe', cwd: process.cwd(), } ); } -} \ No newline at end of file +} \ No newline at end of file diff --git a/api/src/unraid-api/cli/start.command.ts b/api/src/unraid-api/cli/start.command.ts index c716be506..717bcb217 100644 --- a/api/src/unraid-api/cli/start.command.ts +++ b/api/src/unraid-api/cli/start.command.ts @@ -1,9 +1,10 @@ import { execSync } from 'child_process'; import { join } from 'path'; +import { execa } from 'execa'; import { Command, CommandRunner, Option } from 'nest-commander'; -import { PM2_PATH } from '@app/consts'; +import { ECOSYSTEM_PATH, PM2_PATH } from '@app/consts'; import { levels } from '@app/core/log'; import { LogService } from '@app/unraid-api/cli/log.service'; @@ -21,27 +22,23 @@ export class StartCommand extends CommandRunner { } async run(_, options: StartCommandOptions): Promise { - this.logger.debug(options); - this.logger.log( - `Starting unraid-api with command: -${PM2_PATH} start ${join(import.meta.dirname, 'ecosystem.config.json')} --update-env` - ); - - execSync( - `${PM2_PATH} start ${join(import.meta.dirname, '../../', 'ecosystem.config.json')} --update-env`, - { - env: process.env, - stdio: 'inherit', - cwd: process.cwd(), - } - ); + this.logger.info('Starting the Unraid API'); + const envLog = options['log-level'] ? `LOG_LEVEL=${options['log-level']}` : '' + const { stderr, stdout } = await execa(`${envLog} ${PM2_PATH}`.trim(), ['start', ECOSYSTEM_PATH, '--update-env']); + if (stdout) { + this.logger.log(stdout); + } + if (stderr) { + this.logger.error(stderr); + process.exit(1); + } } @Option({ - flags: '--log-level [string]', + flags: `--log-level <${levels.join('|')}>`, description: 'log level to use', }) - parseLogLevel(val: unknown): typeof levels { + parseLogLevel(val: string): typeof levels { return (levels.includes(val as (typeof levels)[number]) ? (val as (typeof levels)[number]) : 'info') as unknown as typeof levels;