import { Attributes } from '@opentelemetry/api'; /** * DiagnosticsMetrics provides a high-level API for recording metrics using * the @vtex/diagnostics-nodejs library. It completely abstracts instrument * management, bucket configuration, and lifecycle. * * Uses a single histogram for all latency measurements with attributes to differentiate. * This follows OpenTelemetry best practices and reduces metric cardinality. * * ## Base Attributes (Request Context) * * DiagnosticsMetrics supports automatic merging of request-scoped "base attributes" * with custom attributes provided in each metric call. This is useful for automatically * including request context (account, status_code, route_id, etc.) in all metrics * recorded during a request lifecycle. * * Use `runWithBaseAttributes()` to set base attributes for a scope. All metric calls * within that scope will automatically include these base attributes, merged with * any custom attributes provided. * * **Important:** Base attributes take precedence over custom attributes. If a custom * attribute has the same key as a base attribute, the custom attribute is silently * dropped and the base attribute value is used. * * @example * ```typescript * const diagnosticsMetrics = new DiagnosticsMetrics() * diagnosticsMetrics.initMetricClient() * * // Record latency with operation type in attributes * const start = process.hrtime() * // ... do work ... * diagnosticsMetrics.recordLatency(process.hrtime(start), { operation: 'api-call', status: '2xx' }) * * // Or from milliseconds * diagnosticsMetrics.recordLatency(42.5, { operation: 'db-query', status: 'success' }) * * // Increment a counter * diagnosticsMetrics.incrementCounter('http_requests_total', 1, { method: 'GET', status: '2xx' }) * * // Set a gauge value * diagnosticsMetrics.setGauge('cache_items_current', 1024, { cache: 'pages' }) * * // Using base attributes for request context * await diagnosticsMetrics.runWithBaseAttributes( * { 'vtex.account.name': 'mystore', status_code: 200 }, * async () => { * // All metrics recorded here will include the base attributes * diagnosticsMetrics.recordLatency(100, { operation: 'custom-op' }) * // Result: { 'vtex.account.name': 'mystore', status_code: 200, operation: 'custom-op' } * } * ) * ``` */ export declare class DiagnosticsMetrics { private metricsClient; private clientInitPromise; private latencyHistogram; private counters; private gauges; constructor(); /** * Initialize the metrics client with timeout handling. * Called automatically in constructor. */ private initMetricClient; /** * Create the single shared histogram for all latency measurements. * Called after metric client is initialized. */ private createLatencyHistogram; /** * Execute a function with base attributes set in the OpenTelemetry context. * All metric calls within the function will automatically include these base attributes, * merged with any custom attributes provided in each call. * * Base attributes take precedence over custom attributes when there are key conflicts. * Conflicting custom attributes are silently dropped. * * @param baseAttributes Base attributes to include in all metrics within the scope * @param fn Function to execute with the base attributes context * @returns The return value of the function * * @example * ```typescript * // In a request middleware * await diagnosticsMetrics.runWithBaseAttributes( * { * 'vtex.account.name': ctx.vtex.account, * status_code: ctx.status, * route_id: ctx.vtex.route.id, * }, * async () => { * await next() * } * ) * * // In app code (custom attributes are merged with base) * diagnosticsMetrics.recordLatency(elapsed, { operation: 'my-operation', status: 'success' }) * // Result includes both base attributes AND custom attributes * ``` */ runWithBaseAttributes(baseAttributes: Attributes, fn: () => T): T; /** * Get the base attributes from the current OpenTelemetry context. * Returns undefined if no base attributes are set. */ private getBaseAttributes; /** * Merge base attributes from context with provided custom attributes. * Base attributes take precedence over custom attributes when there are key conflicts. * * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES before merging. * Custom attributes with keys that conflict with base attributes are silently dropped. * Base attributes are not limited. * * @param customAttributes Custom attributes provided by the caller * @returns Merged attributes (base + non-conflicting limited custom) or undefined if both are empty */ private mergeAttributes; /** * Record a latency measurement using the single shared histogram. * Accepts either an hrtime tuple from process.hrtime() or milliseconds as a number. * Use attributes to differentiate between different operations. * * Base attributes from the current context (set via `runWithBaseAttributes`) are * automatically merged with the provided custom attributes. Base attributes take * precedence - if a custom attribute key conflicts with a base attribute key, * the custom attribute is silently dropped. * * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited. * * @param value Either [seconds, nanoseconds] from process.hrtime() or milliseconds * @param attributes Custom attributes including 'operation' to identify the operation type (max 5 custom attributes) * * @example * ```typescript * const start = process.hrtime() * // ... do work ... * diagnosticsMetrics.recordLatency(process.hrtime(start), { operation: 'api-call', status: '2xx' }) * * // Or with milliseconds * diagnosticsMetrics.recordLatency(42.5, { operation: 'db-query', status: 'success' }) * ``` */ recordLatency(value: [number, number] | number, attributes?: Attributes): void; /** * Increment a counter by a specific value. * Multiple counters are stored by name since counters represent different types of events. * * Base attributes from the current context (set via `runWithBaseAttributes`) are * automatically merged with the provided custom attributes. Base attributes take * precedence - if a custom attribute key conflicts with a base attribute key, * the custom attribute is silently dropped. * * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited. * * @param name Counter name (e.g., 'http_requests_total', 'cache_hits_total') * @param value Amount to increment by (typically 1) * @param attributes Optional custom attributes for the counter (max 5 custom attributes, e.g., { method: 'GET', status: '2xx' }) * * @example * ```typescript * diagnosticsMetrics.incrementCounter('http_requests_total', 1, { method: 'GET', status: '2xx' }) * ``` */ incrementCounter(name: string, value: number, attributes?: Attributes): void; /** * Set a gauge to a specific value (current state). * Multiple gauges are stored by name since gauges represent different types of measurements. * * Base attributes from the current context (set via `runWithBaseAttributes`) are * automatically merged with the provided custom attributes. Base attributes take * precedence - if a custom attribute key conflicts with a base attribute key, * the custom attribute is silently dropped. * * Custom attributes are limited to MAX_CUSTOM_ATTRIBUTES (5). Base attributes are not limited. * * @param name Gauge name (e.g., 'cache_items_current', 'memory_usage_bytes') * @param value Current value * @param attributes Optional custom attributes for the gauge (max 5 custom attributes, e.g., { cache: 'pages' }) * * @example * ```typescript * diagnosticsMetrics.setGauge('cache_items_current', 1024, { cache: 'pages' }) * ``` */ setGauge(name: string, value: number, attributes?: Attributes): void; }