@christiangalsterer/mongodb-driver-prometheus-exporter
Version:
Prometheus exporter to monitor the MongoDB Node.js driver
205 lines • 11.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoDBDriverExporter = void 0;
const prom_client_1 = require("prom-client");
const utils_1 = require("./utils");
const MILLISECONDS_IN_A_SECOND = 1000;
const METRIC_INITIAL_ZERO = 0;
class MongoDBDriverExporter {
register;
mongoClient;
options;
defaultOptions = {
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
mongodbDriverCommandsSecondsHistogramBuckets: [0.001, 0.005, 0.01, 0.02, 0.03, 0.04, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10],
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
waitQueueSecondsHistogramBuckets: [0.001, 0.005, 0.01, 0.02, 0.03, 0.04, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10]
};
// pool metrics
poolSize;
minSize;
maxSize;
checkedOut;
waitQueueSize;
waitQueueSeconds;
MONGODB_DRIVER_POOL_SIZE = 'mongodb_driver_pool_size';
MONGODB_DRIVER_POOL_MIN = 'mongodb_driver_pool_min';
MONGODB_DRIVER_POOL_MAX = 'mongodb_driver_pool_max';
MONGODB_DRIVER_POOL_CHECKEDOUT = 'mongodb_driver_pool_checkedout';
MONGODB_DRIVER_POOL_WAITQUEUESIZE = 'mongodb_driver_pool_waitqueuesize';
MONGODB_DRIVER_POOL_WAITQUEUE_SECONDS = 'mongodb_driver_pool_waitqueue_seconds';
// command metrics
commands;
MONGODB_DRIVER_COMMANDS_SECONDS = 'mongodb_driver_commands_seconds';
constructor(mongoClient, register, options) {
this.mongoClient = mongoClient;
this.register = register;
this.options = { ...this.defaultOptions, ...options };
const prefix = options?.prefix ?? '';
const poolSizeMetric = this.register.getSingleMetric(`${prefix}${this.MONGODB_DRIVER_POOL_SIZE}`);
this.poolSize =
poolSizeMetric instanceof prom_client_1.Gauge
? poolSizeMetric
: new prom_client_1.Gauge({
name: `${prefix}${this.MONGODB_DRIVER_POOL_SIZE}`,
help: 'the current size of the connection pool, including idle and in-use members',
labelNames: (0, utils_1.mergeLabelNamesWithStandardLabels)(['server_address'], this.options.defaultLabels),
registers: [this.register]
});
const minSizeMetric = this.register.getSingleMetric(`${prefix}${this.MONGODB_DRIVER_POOL_MIN}`);
this.minSize =
minSizeMetric instanceof prom_client_1.Gauge
? minSizeMetric
: new prom_client_1.Gauge({
name: `${prefix}${this.MONGODB_DRIVER_POOL_MIN}`,
help: 'the minimum size of the connection pool',
labelNames: (0, utils_1.mergeLabelNamesWithStandardLabels)(['server_address'], this.options.defaultLabels),
registers: [this.register]
});
const maxSizeMetric = this.register.getSingleMetric(`${prefix}${this.MONGODB_DRIVER_POOL_MAX}`);
this.maxSize =
maxSizeMetric instanceof prom_client_1.Gauge
? maxSizeMetric
: new prom_client_1.Gauge({
name: `${prefix}${this.MONGODB_DRIVER_POOL_MAX}`,
help: 'the maximum size of the connection pool',
labelNames: (0, utils_1.mergeLabelNamesWithStandardLabels)(['server_address'], this.options.defaultLabels),
registers: [this.register]
});
const checkedOutMetric = this.register.getSingleMetric(`${prefix}${this.MONGODB_DRIVER_POOL_CHECKEDOUT}`);
this.checkedOut =
checkedOutMetric instanceof prom_client_1.Gauge
? checkedOutMetric
: new prom_client_1.Gauge({
name: `${prefix}${this.MONGODB_DRIVER_POOL_CHECKEDOUT}`,
help: 'the count of connections that are currently in use',
labelNames: (0, utils_1.mergeLabelNamesWithStandardLabels)(['server_address'], this.options.defaultLabels),
registers: [this.register]
});
const waitQueueSizeMetric = this.register.getSingleMetric(`${prefix}${this.MONGODB_DRIVER_POOL_WAITQUEUESIZE}`);
this.waitQueueSize =
waitQueueSizeMetric instanceof prom_client_1.Gauge
? waitQueueSizeMetric
: new prom_client_1.Gauge({
name: `${prefix}${this.MONGODB_DRIVER_POOL_WAITQUEUESIZE}`,
help: 'the current size of the wait queue for a connection from the pool',
labelNames: (0, utils_1.mergeLabelNamesWithStandardLabels)(['server_address'], this.options.defaultLabels),
registers: [this.register]
});
const waitQueueSecondsMetric = this.register.getSingleMetric(`${prefix}${this.MONGODB_DRIVER_POOL_WAITQUEUE_SECONDS}`);
this.waitQueueSeconds =
waitQueueSecondsMetric instanceof prom_client_1.Histogram
? waitQueueSecondsMetric
: new prom_client_1.Histogram({
name: `${prefix}${this.MONGODB_DRIVER_POOL_WAITQUEUE_SECONDS}`,
help: 'Duration of waiting for a connection from the pool',
buckets: this.options.waitQueueSecondsHistogramBuckets,
labelNames: (0, utils_1.mergeLabelNamesWithStandardLabels)(['server_address', 'status'], this.options.defaultLabels),
registers: [this.register]
});
if (this.monitorCommands()) {
const commandsMetric = this.register.getSingleMetric(`${prefix}${this.MONGODB_DRIVER_COMMANDS_SECONDS}`);
this.commands =
commandsMetric instanceof prom_client_1.Histogram
? commandsMetric
: new prom_client_1.Histogram({
name: `${prefix}${this.MONGODB_DRIVER_COMMANDS_SECONDS}`,
help: 'Timer of mongodb commands',
buckets: this.options.mongodbDriverCommandsSecondsHistogramBuckets,
labelNames: (0, utils_1.mergeLabelNamesWithStandardLabels)(['command', 'server_address', 'status'], this.options.defaultLabels),
registers: [this.register]
});
}
}
enableMetrics() {
this.mongoClient.on('connectionPoolCreated', (event) => {
this.onConnectionPoolCreated(event);
});
this.mongoClient.on('connectionPoolClosed', (event) => {
this.onConnectionPoolClosed(event);
});
this.mongoClient.on('connectionCreated', (event) => {
this.onConnectionCreated(event);
});
this.mongoClient.on('connectionClosed', (event) => {
this.onConnectionClosed(event);
});
this.mongoClient.on('connectionCheckOutStarted', (event) => {
this.onConnectionCheckOutStarted(event);
});
this.mongoClient.on('connectionCheckedOut', (event) => {
this.onConnectionCheckedOut(event);
});
this.mongoClient.on('connectionCheckOutFailed', (event) => {
this.onConnectionCheckOutFailed(event);
});
this.mongoClient.on('connectionCheckedIn', (event) => {
this.onConnectionCheckedIn(event);
});
this.options.logger?.info('Successfully enabled connection pool metrics for the MongoDB Node.js driver.');
// command metrics
if (this.monitorCommands()) {
this.mongoClient.on('commandSucceeded', (event) => {
this.onCommandSucceeded(event);
});
this.mongoClient.on('commandFailed', (event) => {
this.onCommandFailed(event);
});
this.options.logger?.info('Successfully enabled command metrics for the MongoDB Node.js driver.');
}
}
monitorCommands() {
return this.mongoClient.options.monitorCommands.valueOf();
}
onConnectionPoolCreated(event) {
this.poolSize.set((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels), METRIC_INITIAL_ZERO);
this.minSize.set((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels), event.options.minPoolSize);
this.maxSize.set((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels), event.options.maxPoolSize);
this.checkedOut.set((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels), METRIC_INITIAL_ZERO);
this.waitQueueSize.set((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels), METRIC_INITIAL_ZERO);
}
onConnectionCreated(event) {
this.poolSize.inc((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels));
}
onConnectionClosed(event) {
this.poolSize.dec((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels));
}
onConnectionCheckOutStarted(event) {
this.waitQueueSize.inc((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels));
}
onConnectionCheckedOut(event) {
this.checkedOut.inc((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels));
this.waitQueueSize.dec((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels));
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (event.durationMS !== undefined) {
// conditional observation for backward compatibility with `mongodb` <6.9.0
this.waitQueueSeconds.observe((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address, status: 'SUCCESS' }, this.options.defaultLabels), event.durationMS / MILLISECONDS_IN_A_SECOND);
}
}
onConnectionCheckOutFailed(event) {
this.waitQueueSize.dec((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels));
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (event.durationMS !== undefined) {
// conditional observation for backward compatibility with `mongodb` <6.9.0
this.waitQueueSeconds.observe((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address, status: 'FAILED' }, this.options.defaultLabels), event.durationMS / MILLISECONDS_IN_A_SECOND);
}
}
onConnectionCheckedIn(event) {
this.checkedOut.dec((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels));
}
onConnectionPoolClosed(event) {
this.poolSize.set((0, utils_1.mergeLabelsWithStandardLabels)({ server_address: event.address }, this.options.defaultLabels), METRIC_INITIAL_ZERO);
this.minSize.reset();
this.maxSize.reset();
this.checkedOut.reset();
this.waitQueueSize.reset();
}
onCommandSucceeded(event) {
this.commands.observe((0, utils_1.mergeLabelsWithStandardLabels)({ command: event.commandName, server_address: event.address, status: 'SUCCESS' }, this.options.defaultLabels), event.duration / MILLISECONDS_IN_A_SECOND);
}
onCommandFailed(event) {
this.commands.observe((0, utils_1.mergeLabelsWithStandardLabels)({ command: event.commandName, server_address: event.address, status: 'FAILED' }, this.options.defaultLabels), event.duration / MILLISECONDS_IN_A_SECOND);
}
}
exports.MongoDBDriverExporter = MongoDBDriverExporter;
//# sourceMappingURL=mongoDBDriverExporter.js.map