diff --git a/src/utils/logger.ts b/src/utils/logger.ts index a203bdb..68b7b2a 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,12 +1,84 @@ import chalk from "chalk"; +interface TimingEntry { + label: string; + startTime: number; + endTime?: number; +} + export class Logger { private verbose: boolean; + private timings: Map = new Map(); constructor() { this.verbose = process.env.VERBOSE === "true"; } + /** + * Start timing an operation + */ + startTimer(label: string): void { + this.timings.set(label, { + label, + startTime: Date.now(), + }); + if (this.verbose) { + console.log(chalk.magenta("⏱"), `Started: ${label}`); + } + } + + /** + * End timing and log the duration + */ + endTimer(label: string): number { + const entry = this.timings.get(label); + if (!entry) { + this.warning(`Timer "${label}" was never started`); + return 0; + } + + const duration = Date.now() - entry.startTime; + entry.endTime = Date.now(); + + // Format duration for display + let durationStr: string; + if (duration < 1000) { + durationStr = `${duration}ms`; + } else if (duration < 60000) { + durationStr = `${(duration / 1000).toFixed(2)}s`; + } else { + const mins = Math.floor(duration / 60000); + const secs = ((duration % 60000) / 1000).toFixed(1); + durationStr = `${mins}m ${secs}s`; + } + + console.log(chalk.magenta("⏱"), `${label}: ${chalk.bold(durationStr)}`); + return duration; + } + + /** + * Get all timing data for analysis + */ + getTimingReport(): { label: string; duration: number }[] { + const report: { label: string; duration: number }[] = []; + for (const [label, entry] of this.timings) { + if (entry.endTime) { + report.push({ + label, + duration: entry.endTime - entry.startTime, + }); + } + } + return report; + } + + /** + * Clear all timing data + */ + clearTimings(): void { + this.timings = new Map(); + } + info(...args: any[]): void { console.log(chalk.blue("ℹ"), ...args); }