export default class PerformanceMonitor {
constructor(logger = null) {
this.logger = logger;
this.metrics = new Map();
}
measureOperation(name, fn) {
const start = performance.now();
try {
const result = fn();
const duration = performance.now() - start;
this._recordMetric(name, duration);
return result;
} catch (error) {
this.logger?.error(`Operation ${name} failed`, error);
throw error;
}
}
async measureAsync(name, fn) {
const start = performance.now();
try {
const result = await fn();
const duration = performance.now() - start;
this._recordMetric(name, duration);
return result;
} catch (error) {
this.logger?.error(`Async operation ${name} failed`, error);
throw error;
}
}
_recordMetric(name, duration) {
if (!this.metrics.has(name)) {
this.metrics.set(name, []);
}
this.metrics.get(name).push(duration);
this.logger?.debug(`[PERF] ${name}: ${duration.toFixed(2)}ms`);
}
getMetrics(name) {
const values = this.metrics.get(name) || [];
return {
count: values.length,
min: Math.min(...values),
max: Math.max(...values),
avg: values.reduce((a, b) => a + b, 0) / values.length,
values
};
}
reportWebVitals() {
if ('web-vital' in window) {
const vitals = window['web-vital'];
this.logger?.info('Core Web Vitals', vitals);
}
}
getAllMetrics() {
const result = {};
for (const [name, values] of this.metrics.entries()) {
result[name] = this.getMetrics(name);
}
return result;
}
reset() {
this.metrics.clear();
}
}