UNPKG

autotel

Version:
278 lines (276 loc) 7.42 kB
import { getConfig } from "./config.js"; import "@opentelemetry/api"; //#region src/metric.ts var Metric = class { serviceName; eventCounter; funnelCounter; outcomeCounter; valueHistogram; logger; collector; /** * Create a new Metrics instance * * @param serviceName - Service name for metric namespacing * @param options - Optional configuration (logger, collector, namespace, metrics) * * @example Basic usage (default 'metrics' namespace) * ```typescript * const metrics = new Metric('checkout'); * // Creates: checkout.metrics.events, checkout.metrics.funnel, etc. * ``` * * @example Custom namespace * ```typescript * const metrics = new Metric('api', { namespace: 'business' }); * // Creates: api.business.events, api.business.funnel, etc. * ``` * * @example Custom metric names and descriptions * ```typescript * const metrics = new Metric('payments', { * metrics: { * outcomes: { * name: 'payments.transactions', * description: 'Payment transaction outcomes', * unit: 'transactions' * }, * value: { * name: 'payments.revenue', * description: 'Payment revenue in USD', * unit: 'USD' * } * } * }); * ``` */ constructor(serviceName, options = {}) { this.serviceName = serviceName; this.logger = options.logger; this.collector = options.collector; const meter = getConfig().meter; const namespace = options.namespace || "metrics"; const metricsConfig = options.metrics || {}; const eventsConfig = metricsConfig.events || {}; this.eventCounter = meter.createCounter(eventsConfig.name || `${serviceName}.${namespace}.events`, { description: eventsConfig.description || "Count of business events", unit: eventsConfig.unit || "1" }); const funnelConfig = metricsConfig.funnel || {}; this.funnelCounter = meter.createCounter(funnelConfig.name || `${serviceName}.${namespace}.funnel`, { description: funnelConfig.description || "Conversion funnel tracking", unit: funnelConfig.unit || "1" }); const outcomesConfig = metricsConfig.outcomes || {}; this.outcomeCounter = meter.createCounter(outcomesConfig.name || `${serviceName}.${namespace}.outcomes`, { description: outcomesConfig.description || "Outcome tracking (success/failure)", unit: outcomesConfig.unit || "1" }); const valueConfig = metricsConfig.value || {}; this.valueHistogram = meter.createHistogram(valueConfig.name || `${serviceName}.${namespace}.value`, { description: valueConfig.description || "Value metrics (revenue, counts, etc.)", unit: valueConfig.unit || "1" }); } /** * Track a business event as a metric * * Use this for tracking user actions, business events, product usage as metrics: * - "user.signup" * - "order.completed" * - "feature.used" * * @example * ```typescript * // Track user signup as metric * metrics.trackEvent('user.signup', { * userId: '123', * plan: 'pro' * }) * * // Track order as metric * metrics.trackEvent('order.completed', { * orderId: 'ord_123', * amount: 99.99 * }) * ``` */ trackEvent(eventName, attributes) { const attrs = { service: this.serviceName, event: eventName, ...attributes }; this.eventCounter.add(1, attrs); this.logger?.info({ event: eventName, attributes }, "Metric event tracked"); this.collector?.recordEvent({ event: eventName, attributes, service: this.serviceName, timestamp: Date.now() }); } /** * Track conversion funnel steps as metrics * * Monitor where users drop off in multi-step processes. * * @example * ```typescript * // Track signup funnel * metrics.trackFunnelStep('signup', 'started', { userId: '123' }) * metrics.trackFunnelStep('signup', 'email_verified', { userId: '123' }) * metrics.trackFunnelStep('signup', 'completed', { userId: '123' }) * * // Track checkout flow * metrics.trackFunnelStep('checkout', 'started', { cartValue: 99.99 }) * metrics.trackFunnelStep('checkout', 'payment_info', { cartValue: 99.99 }) * metrics.trackFunnelStep('checkout', 'completed', { cartValue: 99.99 }) * ``` */ trackFunnelStep(funnelName, status, attributes) { const attrs = { service: this.serviceName, funnel: funnelName, status, ...attributes }; this.funnelCounter.add(1, attrs); this.logger?.info({ funnel: funnelName, status, attributes }, "Funnel step tracked"); this.collector?.recordFunnelStep({ funnel: funnelName, status, attributes, service: this.serviceName, timestamp: Date.now() }); } /** * Track outcomes (success/failure/partial) as metrics * * Monitor success rates of critical operations. * * @example * ```typescript * // Track email delivery * metrics.trackOutcome('email.delivery', 'success', { * recipientType: 'user', * emailType: 'welcome' * }) * * metrics.trackOutcome('email.delivery', 'failure', { * recipientType: 'user', * errorCode: 'invalid_email' * }) * * // Track payment processing * metrics.trackOutcome('payment.process', 'success', { amount: 99.99 }) * metrics.trackOutcome('payment.process', 'failure', { error: 'insufficient_funds' }) * ``` */ trackOutcome(operationName, status, attributes) { const attrs = { service: this.serviceName, operation: operationName, status, ...attributes }; this.outcomeCounter.add(1, attrs); this.logger?.info({ operation: operationName, status, attributes }, "Outcome tracked"); this.collector?.recordOutcome({ operation: operationName, status, attributes, service: this.serviceName, timestamp: Date.now() }); } /** * Track value metrics * * Record numerical values like revenue, transaction amounts, * item counts, processing times, engagement scores, etc. * * @example * ```typescript * // Track revenue * metrics.trackValue('order.revenue', 149.99, { * currency: 'USD', * productCategory: 'electronics' * }) * * // Track items per cart * metrics.trackValue('cart.item_count', 5, { * userId: '123' * }) * * // Track processing time * metrics.trackValue('api.response_time', 250, { * unit: 'ms', * endpoint: '/api/checkout' * }) * ``` */ trackValue(metricName, value, attributes) { const attrs = { service: this.serviceName, metric: metricName, ...attributes }; this.valueHistogram.record(value, attrs); this.logger?.debug({ metric: metricName, value, attributes }, "Value metric tracked"); this.collector?.recordValue({ metric: metricName, value, attributes, service: this.serviceName, timestamp: Date.now() }); } }; /** * Global metrics instances (singleton pattern) */ const metricsInstances = /* @__PURE__ */ new Map(); /** * Get or create a Metrics instance for a service * * @param serviceName - Service name for metric namespacing * @param logger - Optional logger * @returns Metrics instance * * @example * ```typescript * const metrics = getMetrics('checkout') * metrics.trackEvent('order.completed', { orderId: '123' }) * ``` */ function getMetrics(serviceName, logger) { if (!metricsInstances.has(serviceName)) metricsInstances.set(serviceName, new Metric(serviceName, { logger })); return metricsInstances.get(serviceName); } /** * Reset all metrics instances (mainly for testing) */ function resetMetrics() { metricsInstances.clear(); } //#endregion export { Metric, getMetrics, resetMetrics }; //# sourceMappingURL=metric.js.map