100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
import { getGlobalErrorHandler } from '@/lib/infrastructure/GlobalErrorHandler';
|
|
import { getGlobalApiLogger } from '@/lib/infrastructure/ApiRequestLogger';
|
|
import { ApiError } from '@/lib/api/base/ApiError';
|
|
import { Result } from '@/lib/contracts/Result';
|
|
import { DomainError, Service } from '@/lib/contracts/services/Service';
|
|
import { getWebsiteServerEnv } from '@/lib/config/env';
|
|
|
|
export interface ErrorStats {
|
|
totalErrors: number;
|
|
errorsByType: Record<string, number>;
|
|
errorsByTime: Array<{ time: string; count: number }>;
|
|
recentErrors: Array<{
|
|
timestamp: string;
|
|
message: string;
|
|
type: string;
|
|
context?: unknown;
|
|
}>;
|
|
apiStats: {
|
|
totalRequests: number;
|
|
successful: number;
|
|
failed: number;
|
|
averageDuration: number;
|
|
slowestRequests: Array<{ url: string; duration: number }>;
|
|
};
|
|
environment: {
|
|
mode: string;
|
|
version?: string;
|
|
buildTime?: string;
|
|
};
|
|
}
|
|
|
|
export class ErrorAnalyticsService implements Service {
|
|
static getErrorAnalyticsStats(): ErrorStats {
|
|
const globalHandler = getGlobalErrorHandler();
|
|
const apiLogger = getGlobalApiLogger();
|
|
|
|
const errorHistory = globalHandler.getErrorHistory();
|
|
const errorStats = globalHandler.getStats();
|
|
const apiStats = apiLogger.getStats();
|
|
|
|
// Group errors by time (last 10 minutes)
|
|
const timeGroups = new Map<string, number>();
|
|
const now = Date.now();
|
|
const tenMinutesAgo = now - (10 * 60 * 1000);
|
|
|
|
errorHistory.forEach(entry => {
|
|
const entryTime = new Date(entry.timestamp).getTime();
|
|
if (entryTime >= tenMinutesAgo) {
|
|
const timeKey = new Date(entry.timestamp).toLocaleTimeString();
|
|
timeGroups.set(timeKey, (timeGroups.get(timeKey) || 0) + 1);
|
|
}
|
|
});
|
|
|
|
const errorsByTime = Array.from(timeGroups.entries())
|
|
.map(([time, count]) => ({ time, count }))
|
|
.sort((a, b) => a.time.localeCompare(b.time));
|
|
|
|
const recentErrors = errorHistory.slice(-10).reverse().map(entry => ({
|
|
timestamp: entry.timestamp,
|
|
message: entry.error.message,
|
|
type: entry.error instanceof ApiError ? entry.error.type : entry.error.name || 'Error',
|
|
context: entry.context,
|
|
}));
|
|
|
|
const slowestRequests = apiLogger.getSlowestRequests(5).map(log => ({
|
|
url: log.url,
|
|
duration: log.response?.duration || 0,
|
|
}));
|
|
|
|
const env = getWebsiteServerEnv();
|
|
|
|
return {
|
|
totalErrors: errorStats.total,
|
|
errorsByType: errorStats.byType,
|
|
errorsByTime,
|
|
recentErrors,
|
|
apiStats: {
|
|
totalRequests: apiStats.total,
|
|
successful: apiStats.successful,
|
|
failed: apiStats.failed,
|
|
averageDuration: apiStats.averageDuration,
|
|
slowestRequests,
|
|
},
|
|
environment: {
|
|
mode: env.NODE_ENV || 'unknown',
|
|
version: process.env.NEXT_PUBLIC_APP_VERSION,
|
|
buildTime: process.env.NEXT_PUBLIC_BUILD_TIME,
|
|
},
|
|
};
|
|
}
|
|
|
|
async getErrorAnalyticsStats(): Promise<Result<ErrorStats, DomainError>> {
|
|
try {
|
|
return Result.ok(ErrorAnalyticsService.getErrorAnalyticsStats());
|
|
} catch (error: unknown) {
|
|
return Result.err({ type: 'serverError', message: (error as Error).message || 'Failed to get error analytics stats' });
|
|
}
|
|
}
|
|
}
|