@revmax/agent-sdk
Version:
Official Node.js SDK for RevMax - billing, customer management, and usage tracking
162 lines • 5.75 kB
JavaScript
"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