UNPKG

couchbase

Version:

The official Couchbase Node.js Client Library.

227 lines (226 loc) 7.41 kB
"use strict"; /** * @internal */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.LoggingMeter = void 0; const hdr = __importStar(require("hdr-histogram-js")); const errors_1 = require("./errors"); const observabilitytypes_1 = require("./observabilitytypes"); /** * Internal class for recording metric values using HDR histograms. * * @internal */ class LoggingValueRecorder { constructor() { this._percentiles = [50.0, 90.0, 99.0, 99.9, 100.0]; this._histogram = hdr.build({ lowestDiscernibleValue: 1, // 1 microsecond highestTrackableValue: 30000000, // 30 seconds numberOfSignificantValueDigits: 3, }); } /** * Records a metric value. * * @param value - The value to record (typically latency in microseconds). */ recordValue(value) { this._histogram.recordValue(value); } /** * Gets the current percentile values and resets the histogram. * * @returns The percentile report containing total count and percentile values. */ getPercentilesAndReset() { const mappedPercentiles = {}; for (const p of this._percentiles) { mappedPercentiles[p.toString()] = this._histogram.getValueAtPercentile(p); } const result = { total_count: this._histogram.totalCount, percentiles_us: mappedPercentiles, }; this._histogram.reset(); return result; } } /** * Internal class for periodically emitting meter reports. * * @internal */ class LoggingMeterReporter { constructor(loggingMeter, emitInterval, logger) { this._loggingMeter = loggingMeter; this._emitInterval = emitInterval; this._logger = logger; this._stopped = false; } /** * @internal */ start() { this._timerId = setInterval(this.report.bind(this), this._emitInterval); // let the process exit even if the reporter has not been shutdown this._timerId.unref(); this._stopped = false; } /** * @internal */ stop() { if (this._stopped) { return; } this._stopped = true; clearInterval(this._timerId); } /** * @internal */ report() { const report = this._loggingMeter.createReport(); if (report) { this._logger.info(JSON.stringify(report)); } } /** * @internal */ toJSON() { return {}; } } /** * A logging-based meter implementation that records metrics using HDR histograms * and periodically reports percentile statistics. * * @internal */ class LoggingMeter { /** * Creates a new LoggingMeter with the specified flush interval. * * @param logger - The logger to be used by the LoggingMeter. * @param emitInterval - The interval in milliseconds between reports (default: 600000ms = 10 minutes). */ constructor(logger, emitInterval) { this._recorders = new Map(); this._emitInterval = emitInterval !== null && emitInterval !== void 0 ? emitInterval : 600000; // Default to 10 minutes // Initialize recorders map for each service type for (const serviceType of Object.values(observabilitytypes_1.ServiceName)) { this._recorders.set(serviceType, new Map()); } this._reporter = new LoggingMeterReporter(this, this._emitInterval, logger); this._reporter.start(); } /** * Gets the meter's LoggingMeterReporter. * * @internal */ get reporter() { return this._reporter; } /** * Gets or creates a value recorder for the specified metric name and tags. * * @param _name - Unused. * @param tags - Key-value pairs that categorize the metric. * @returns A value recorder for recording values. */ valueRecorder(_name, tags) { // The ObservabilityHandler, at least for now, only passes in OpAttributeName.MeterNameOpDuration for the name // for OTel compat. However, for the loging meter we care about the opName. const serviceTag = tags[observabilitytypes_1.OpAttributeName.Service]; if (!Object.values(observabilitytypes_1.ServiceName).includes(serviceTag)) { throw new errors_1.MeterError(new Error(`Invalid service type: ${serviceTag}`)); } const service = serviceTag; const opMap = this._recorders.get(service); const opName = tags[observabilitytypes_1.OpAttributeName.OperationName]; let recorder = opMap.get(opName); if (!recorder) { recorder = new LoggingValueRecorder(); opMap.set(opName, recorder); } return recorder; } /** * Creates a report of all recorded metrics and resets the histograms. * * @returns The logging meter report with percentile statistics. */ createReport() { const report = { meta: { emit_interval_s: this._emitInterval / 1000, }, operations: {}, }; for (const [serviceType, opMap] of this._recorders.entries()) { const svcReport = {}; for (const [opName, recorder] of opMap.entries()) { const percentileReport = recorder.getPercentilesAndReset(); if (percentileReport.total_count > 0) { svcReport[opName] = percentileReport; } } if (Object.keys(svcReport).length > 0) { report.operations[serviceType] = svcReport; } } if (Object.keys(report.operations).length === 0) { return null; } return report; } /** * Stops the threshold logging reporter and cleans up resources. * * This method should be called when shutting down the application or when * the tracer is no longer needed to ensure the periodic reporting timer * is properly cleared. */ cleanup() { try { this._reporter.stop(); } catch (_e) { // Don't raise exceptions during shutdown } } /** * @internal */ toJSON() { return { emitInterval: this._emitInterval }; } } exports.LoggingMeter = LoggingMeter;