couchbase
Version:
The official Couchbase Node.js Client Library.
227 lines (226 loc) • 7.41 kB
JavaScript
"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;