UNPKG

@revmax/agent-sdk

Version:

Official Node.js SDK for RevMax - billing, customer management, and usage tracking

162 lines 5.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Telemetry = exports.defaultTelemetryHandler = void 0; const uuid_1 = require("uuid"); const logger_1 = require("./logger"); /** * Default telemetry handler just logs to the console */ const defaultTelemetryHandler = (metrics) => { console.log(`[TELEMETRY] ${metrics.method} ${metrics.path} - ${metrics.duration}ms (${metrics.success ? 'SUCCESS' : 'FAILED'})`); }; exports.defaultTelemetryHandler = defaultTelemetryHandler; /** * SDK Telemetry class for tracking performance metrics */ class Telemetry { /** * Create a new telemetry instance * @param options - Telemetry configuration options * @param logger - Logger instance */ constructor(options, logger) { this.activeRequests = new Map(); // Metrics aggregation this.requestCount = 0; this.successCount = 0; this.errorCount = 0; this.totalDuration = 0; // Error tracking (errorType -> count) this.errorTypes = new Map(); this.enabled = options?.enabled ?? false; this.sampleRate = options?.sampleRate ?? 1; this.handler = options?.handler ?? exports.defaultTelemetryHandler; this.logger = logger || new logger_1.Logger(); } /** * Check if telemetry should be collected for this request * @returns Whether to collect telemetry */ shouldCollect() { if (!this.enabled) return false; return Math.random() <= this.sampleRate; } /** * Generate a request ID * @returns Unique request ID */ generateRequestId() { return (0, uuid_1.v4)(); } /** * Normalize API path to remove specific IDs * @param path - Raw API path * @returns Normalized path */ normalizePath(path) { if (!path) return ''; // Ensure path starts with / const normalizedPath = path.startsWith('/') ? path : `/${path}`; // Replace UUID patterns with :id return (normalizedPath // Replace UUIDs .replace(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '/:id') // Replace numeric IDs .replace(/\/\d+(?=\/|$)/g, '/:id')); } /** * Start tracking a request * @param method - HTTP method * @param path - Request path * @param requestId - Optional request ID (generated if not provided) * @returns Request ID and whether telemetry is being collected */ startRequest(method, path, requestId) { const shouldTrack = this.shouldCollect(); const id = requestId || this.generateRequestId(); if (shouldTrack) { const normalizedPath = this.normalizePath(path); const metrics = { requestId: id, method: method.toUpperCase(), path: normalizedPath, startTime: Date.now(), }; this.activeRequests.set(id, metrics); this.logger.debug(`Started tracking request ${id}: ${method} ${normalizedPath}`); } return { requestId: id, isTracked: shouldTrack }; } /** * End tracking a request * @param requestId - Request ID * @param statusCode - HTTP status code * @param error - Error object if request failed * @param retryCount - Number of retry attempts */ endRequest(requestId, statusCode, error, retryCount) { const metrics = this.activeRequests.get(requestId); if (!metrics) return; // Calculate metrics metrics.endTime = Date.now(); metrics.duration = metrics.endTime - metrics.startTime; metrics.statusCode = statusCode; metrics.success = !error && (statusCode ? statusCode < 400 : true); metrics.retryCount = retryCount || 0; if (error) { metrics.errorMessage = error.message; metrics.errorType = error.name || 'UnknownError'; // Track error types const currentCount = this.errorTypes.get(metrics.errorType) || 0; this.errorTypes.set(metrics.errorType, currentCount + 1); this.errorCount++; } else { this.successCount++; } this.requestCount++; this.totalDuration += metrics.duration; // Call the telemetry handler this.handler(metrics); // Remove from active requests this.activeRequests.delete(requestId); this.logger.debug(`Completed tracking request ${requestId}: ${metrics.duration}ms, success: ${metrics.success}`); } /** * Get current telemetry statistics * @returns Aggregated metrics */ getStats() { const successRate = this.requestCount > 0 ? this.successCount / this.requestCount : 1; const averageDuration = this.requestCount > 0 ? this.totalDuration / this.requestCount : 0; // Convert error types map to object const errorBreakdown = {}; this.errorTypes.forEach((count, type) => { errorBreakdown[type] = count; }); return { requestCount: this.requestCount, successCount: this.successCount, errorCount: this.errorCount, successRate, averageDuration, errorBreakdown, }; } /** * Reset all metrics */ resetStats() { this.requestCount = 0; this.successCount = 0; this.errorCount = 0; this.totalDuration = 0; this.errorTypes.clear(); this.logger.debug('Telemetry stats reset'); } } exports.Telemetry = Telemetry; //# sourceMappingURL=telemetry.js.map