115 lines
3.7 KiB
TypeScript
Executable file
115 lines
3.7 KiB
TypeScript
Executable file
/**
|
|
* Logging utility for orchestration scripts
|
|
*/
|
|
|
|
import chalk from 'chalk';
|
|
|
|
export class Logger {
|
|
private context: string;
|
|
|
|
/**
|
|
* Global silent mode flag - when true, all Logger instances suppress output.
|
|
* Use Logger.setSilent(true) to enable, typically for CI mode.
|
|
*/
|
|
private static globalSilent = false;
|
|
|
|
/**
|
|
* Set global silent mode for all Logger instances.
|
|
* Call with `true` before any logging to suppress output.
|
|
*/
|
|
static setSilent(silent: boolean): void {
|
|
Logger.globalSilent = silent;
|
|
}
|
|
|
|
/**
|
|
* Check if global silent mode is enabled.
|
|
*/
|
|
static isSilent(): boolean {
|
|
return Logger.globalSilent;
|
|
}
|
|
|
|
constructor(context: string = 'Orchestrator') {
|
|
this.context = context;
|
|
}
|
|
|
|
private timestamp(): string {
|
|
return new Date().toISOString().split('T')[1]!.split('.')[0]!;
|
|
}
|
|
|
|
private formatMessage(level: string, message: string, color: (text: string) => string): string {
|
|
return `${chalk.gray(this.timestamp())} ${color(`[${level}]`)} ${chalk.cyan(`[${this.context}]`)} ${message}`;
|
|
}
|
|
|
|
info(message: string): void {
|
|
if (Logger.globalSilent) return;
|
|
console.log(this.formatMessage('INFO', message, chalk.blue));
|
|
}
|
|
|
|
success(message: string): void {
|
|
if (Logger.globalSilent) return;
|
|
console.log(this.formatMessage('SUCCESS', message, chalk.green));
|
|
}
|
|
|
|
warn(message: string): void {
|
|
if (Logger.globalSilent) return;
|
|
console.warn(this.formatMessage('WARN', message, chalk.yellow));
|
|
}
|
|
|
|
error(message: string, error?: Error): void {
|
|
if (Logger.globalSilent) return;
|
|
console.error(this.formatMessage('ERROR', message, chalk.red));
|
|
if (error) {
|
|
console.error(chalk.gray(error.stack || error.message));
|
|
}
|
|
}
|
|
|
|
debug(message: string): void {
|
|
if (Logger.globalSilent) return;
|
|
if (process.env.DEBUG) {
|
|
console.log(this.formatMessage('DEBUG', message, chalk.magenta));
|
|
}
|
|
}
|
|
|
|
stage(stageName: string, description?: string): void {
|
|
if (Logger.globalSilent) return;
|
|
console.log('\n' + chalk.bold.cyan(`━━━ Stage: ${stageName} ${description ? `- ${description}` : ''} ━━━`));
|
|
}
|
|
|
|
section(title: string): void {
|
|
if (Logger.globalSilent) return;
|
|
console.log('\n' + chalk.bold.white(`▸ ${title}`));
|
|
}
|
|
|
|
serviceStart(serviceId: string): void {
|
|
if (Logger.globalSilent) return;
|
|
console.log(` ${chalk.gray('↗')} Starting ${chalk.white(serviceId)}...`);
|
|
}
|
|
|
|
serviceHealth(serviceId: string, healthy: boolean, responseTime?: number): void {
|
|
if (Logger.globalSilent) return;
|
|
if (healthy) {
|
|
const time = responseTime ? ` ${chalk.gray(`(${responseTime}ms)`)}` : '';
|
|
console.log(` ${chalk.green('✓')} ${chalk.white(serviceId)} healthy${time}`);
|
|
} else {
|
|
console.log(` ${chalk.red('✗')} ${chalk.white(serviceId)} unhealthy`);
|
|
}
|
|
}
|
|
|
|
progress(current: number, total: number, label: string): void {
|
|
if (Logger.globalSilent) return;
|
|
const percentage = Math.round((current / total) * 100);
|
|
const bar = '█'.repeat(Math.floor(percentage / 5)) + '░'.repeat(20 - Math.floor(percentage / 5));
|
|
console.log(` ${chalk.gray(bar)} ${percentage}% ${label}`);
|
|
}
|
|
|
|
summary(title: string, items: Array<{ label: string; value: string | number; color?: 'green' | 'red' | 'yellow' }>): void {
|
|
if (Logger.globalSilent) return;
|
|
console.log('\n' + chalk.bold.white(`━━━ ${title} ━━━`));
|
|
for (const item of items) {
|
|
const colorFn = item.color === 'green' ? chalk.green : item.color === 'red' ? chalk.red : item.color === 'yellow' ? chalk.yellow : chalk.white;
|
|
console.log(` ${chalk.gray('•')} ${item.label}: ${colorFn(String(item.value))}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
export const logger = new Logger();
|