Files
gridpilot.gg/apps/website/lib/services/error/ErrorAnalyticsService.ts
2026-01-16 01:00:03 +01:00

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' });
}
}
}