Initial commit

This commit is contained in:
theshy
2025-07-31 17:05:07 +08:00
parent 8fab3b19cc
commit 24f21144ab
91 changed files with 16311 additions and 159 deletions

193
lib/utils/performance.ts Normal file
View File

@ -0,0 +1,193 @@
import { logger } from "./logger";
export interface PerformanceMetric {
name: string;
duration: number;
timestamp: number;
metadata?: Record<string, unknown>;
}
class PerformanceMonitor {
private metrics: PerformanceMetric[] = [];
private maxMetrics = 1000;
/**
* 测量函数执行时间
*/
async measure<T>(
name: string,
fn: () => Promise<T>,
metadata?: Record<string, unknown>
): Promise<T> {
const startTime = Date.now();
try {
const result = await fn();
const duration = Date.now() - startTime;
this.recordMetric(name, duration, metadata);
return result;
} catch (error) {
const duration = Date.now() - startTime;
this.recordMetric(`${name}_error`, duration, {
...metadata,
error: true,
});
throw error;
}
}
/**
* 同步测量函数执行时间
*/
measureSync<T>(
name: string,
fn: () => T,
metadata?: Record<string, unknown>
): T {
const startTime = Date.now();
try {
const result = fn();
const duration = Date.now() - startTime;
this.recordMetric(name, duration, metadata);
return result;
} catch (error) {
const duration = Date.now() - startTime;
this.recordMetric(`${name}_error`, duration, {
...metadata,
error: true,
});
throw error;
}
}
/**
* 记录性能指标
*/
recordMetric(
name: string,
duration: number,
metadata?: Record<string, unknown>
): void {
const metric: PerformanceMetric = {
name,
duration,
timestamp: Date.now(),
metadata,
};
this.metrics.push(metric);
// 限制指标数量
if (this.metrics.length > this.maxMetrics) {
this.metrics = this.metrics.slice(-this.maxMetrics / 2);
}
// 记录慢查询
if (duration > 1000) {
logger.warn("Slow operation detected", {
name,
duration,
metadata,
});
}
}
/**
* 获取性能统计
*/
getStats(): {
totalMetrics: number;
averageDuration: number;
slowestOperations: PerformanceMetric[];
fastestOperations: PerformanceMetric[];
operationCounts: Record<string, number>;
} {
if (this.metrics.length === 0) {
return {
totalMetrics: 0,
averageDuration: 0,
slowestOperations: [],
fastestOperations: [],
operationCounts: {},
};
}
const totalDuration = this.metrics.reduce(
(sum, metric) => sum + metric.duration,
0
);
const averageDuration = totalDuration / this.metrics.length;
// 按名称分组统计
const operationCounts: Record<string, number> = {};
this.metrics.forEach((metric) => {
operationCounts[metric.name] = (operationCounts[metric.name] || 0) + 1;
});
// 获取最慢的操作
const slowestOperations = [...this.metrics]
.sort((a, b) => b.duration - a.duration)
.slice(0, 10);
// 获取最快的操作
const fastestOperations = [...this.metrics]
.sort((a, b) => a.duration - b.duration)
.slice(0, 10);
return {
totalMetrics: this.metrics.length,
averageDuration,
slowestOperations,
fastestOperations,
operationCounts,
};
}
/**
* 清理旧指标
*/
cleanup(maxAge: number = 24 * 60 * 60 * 1000): void {
const cutoff = Date.now() - maxAge;
this.metrics = this.metrics.filter((metric) => metric.timestamp > cutoff);
}
/**
* 导出性能报告
*/
generateReport(): string {
const stats = this.getStats();
return `
Performance Report
==================
Total Metrics: ${stats.totalMetrics}
Average Duration: ${stats.averageDuration.toFixed(2)}ms
Slowest Operations:
${stats.slowestOperations
.map((op) => ` ${op.name}: ${op.duration}ms`)
.join("\n")}
Operation Counts:
${Object.entries(stats.operationCounts)
.sort(([, a], [, b]) => b - a)
.map(([name, count]) => ` ${name}: ${count}`)
.join("\n")}
`.trim();
}
}
export const performanceMonitor = new PerformanceMonitor();
// 定期清理旧指标
if (typeof window === "undefined") {
setInterval(() => {
performanceMonitor.cleanup();
}, 60 * 60 * 1000); // 每小时清理一次
}