kuzzle-plugin-prometheus
Version:
Kuzzle plugin: monitoring Kuzzle using Prometheus
151 lines • 6.9 kB
JavaScript
"use strict";
/*
* Kuzzle, a backend software, self-hostable and ready to use
* to power modern apps
*
* Copyright 2015-2021 Kuzzle
* mailto: support AT kuzzle.io
* website: http://kuzzle.io
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.MetricService = void 0;
const prom_client_1 = require("prom-client");
/**
* MetricService is a service to handle metrics from the Kuzzle API and the application.
* @property {{ core: CoreMetrics, requestDuration?: Histogram<string> }} metrics - The application metrics to register.
* @property {{[key: string]: Registry}} registries - The Prometheus registry to register metrics.
*/
class MetricService {
/**
* @param {PrometheusPluginConfiguration} config - The plugin configuration
*/
constructor(config) {
this.labels = config.labels;
this.registries = {
core: new prom_client_1.Registry(),
};
this.metrics = {
core: {
api: {
concurrentRequests: new prom_client_1.Gauge({
name: `${config.core.prefix}api_concurrent_requests`,
help: 'Number of concurrent requests',
labelNames: Object.keys(this.labels),
registers: [this.registries.core]
}),
pendingRequests: new prom_client_1.Gauge({
name: `${config.core.prefix}api_pending_requests`,
help: 'Number of pending requests',
labelNames: Object.keys(this.labels),
registers: [this.registries.core]
}),
},
network: {
connections: new prom_client_1.Gauge({
name: `${config.core.prefix}network_connections`,
help: 'Number of connections',
labelNames: ['protocol', ...Object.keys(this.labels)],
registers: [this.registries.core]
}),
},
realtime: {
rooms: new prom_client_1.Gauge({
name: `${config.core.prefix}realtime_rooms`,
help: 'Number of rooms',
labelNames: Object.keys(this.labels),
registers: [this.registries.core]
}),
subscriptions: new prom_client_1.Gauge({
name: `${config.core.prefix}realtime_subscriptions`,
help: 'Number of subscriptions',
labelNames: Object.keys(this.labels),
registers: [this.registries.core]
}),
},
},
};
if (config.core.monitorRequestDuration) {
// Need to be registered in a separate registry to avoid
// the core registry resetting in updateCoreMetrics
this.registries.requestDuration = new prom_client_1.Registry();
this.metrics.requestDuration = new prom_client_1.Histogram({
name: `${config.core.prefix}api_request_duration_ms`,
help: 'Duration of Kuzzle requests in ms',
labelNames: ['action', 'controller', 'protocol', 'status', ...Object.keys(this.labels)],
registers: [this.registries.requestDuration],
buckets: [0.10, 5, 15, 50, 100, 200, 300, 400, 500]
});
}
if (config.default.enabled) {
this.registries.default = new prom_client_1.Registry();
(0, prom_client_1.collectDefaultMetrics)({
register: this.registries.default,
prefix: config.default.prefix,
labels: this.labels,
eventLoopMonitoringPrecision: config.default.eventLoopMonitoringPrecision,
gcDurationBuckets: config.default.gcDurationBuckets,
});
}
}
/**
* Update the Prometheus coreMetrics with from the server:metrics JSON response
* @param {JSONObject} jsonMetrics - The server:metrics JSON response
*/
updateCoreMetrics(jsonMetrics) {
// Past metrics are oudated, so we need to reset them
this.registries.core.resetMetrics();
for (const component of Object.keys(jsonMetrics)) {
for (const metric of Object.keys(jsonMetrics[component])) {
if (typeof this.metrics.core[component][metric] === 'undefined') {
continue;
}
if (typeof jsonMetrics[component][metric] === 'number') {
this.metrics.core[component][metric].set(this.labels, jsonMetrics[component][metric]);
}
// Only for network.connections metric since we label it using protocol name
if (typeof jsonMetrics[component][metric] === 'object') {
for (const protocol of Object.keys(jsonMetrics[component][metric])) {
this.metrics.core[component][metric].set({ protocol, ...this.labels }, jsonMetrics[component][metric][protocol]);
}
}
}
}
}
/**
* Merge all the Prometheus registries into one and returns metrics as Prometheus text format
* @returns {string} All the regitries metrics formatted as a Prometheus text
*/
getMetrics() {
return prom_client_1.Registry.merge(Object.values(this.registries)).metrics();
}
/**
* Returns the content type used to export metrics to Prometheus
* @returns {string} The content type used to export metrics to Prometheus
*/
getPrometheusContentType() {
return this.registries.core.contentType;
}
/**
* Record response time in the Prometheus responseTime histogram
* @param {number} time - Time in ms
* @param {{[key: string]: string | number}} labels - Labels to add to the metric
*/
recordResponseTime(time, labels) {
this.metrics.requestDuration.labels({ ...labels, ...this.labels }).observe(time);
}
}
exports.MetricService = MetricService;
//# sourceMappingURL=MetricService.js.map