UNPKG

@prometheus-io/codemirror-promql

Version:
427 lines 17.4 kB
"use strict"; // Copyright 2021 The Prometheus Authors // 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 // // http://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. var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CachedPrometheusClient = exports.HTTPPrometheusClient = void 0; var parser_1 = require("../parser"); var lru_cache_1 = require("lru-cache"); // These are status codes where the Prometheus API still returns a valid JSON body, // with an error encoded within the JSON. var badRequest = 400; var unprocessableEntity = 422; var serviceUnavailable = 503; // HTTPPrometheusClient is the HTTP client that should be used to get some information from the different endpoint provided by prometheus. var HTTPPrometheusClient = /** @class */ (function () { function HTTPPrometheusClient(config) { this.httpMethod = 'POST'; this.apiPrefix = '/api/v1'; // For some reason, just assigning via "= fetch" here does not end up executing fetch correctly // when calling it, thus the indirection via another function wrapper. this.fetchFn = function (input, init) { return fetch(input, init); }; this.requestHeaders = new Headers(); this.abortControllers = new Set(); this.url = config.url ? config.url : ''; this.errorHandler = config.httpErrorHandler; this.lookbackInterval = config.lookbackInterval; if (config.fetchFn) { this.fetchFn = config.fetchFn; } if (config.httpMethod) { this.httpMethod = config.httpMethod; } if (config.apiPrefix) { this.apiPrefix = config.apiPrefix; } if (config.requestHeaders) { this.requestHeaders = config.requestHeaders; } } HTTPPrometheusClient.prototype.labelNames = function (metricName) { var _this = this; var params = new URLSearchParams(); if (this.lookbackInterval) { var end = new Date(); var start = new Date(end.getTime() - this.lookbackInterval); params.set('start', start.toISOString()); params.set('end', end.toISOString()); } if (metricName && metricName.length > 0) { params.set('match[]', (0, parser_1.labelMatchersToString)(metricName)); } var request = this.buildRequest(this.labelsEndpoint(), params); // See https://prometheus.io/docs/prometheus/latest/querying/api/#getting-label-names return this.fetchAPI(request.uri, { method: this.httpMethod, body: request.body, }).catch(function (error) { if (_this.errorHandler) { _this.errorHandler(error); } return []; }); }; // labelValues return a list of the value associated to the given labelName. // In case a metric is provided, then the list of values is then associated to the couple <MetricName, LabelName> HTTPPrometheusClient.prototype.labelValues = function (labelName, metricName, matchers) { var _this = this; var params = new URLSearchParams(); if (this.lookbackInterval) { var end = new Date(); var start = new Date(end.getTime() - this.lookbackInterval); params.set('start', start.toISOString()); params.set('end', end.toISOString()); } if (metricName && metricName.length > 0) { params.set('match[]', (0, parser_1.labelMatchersToString)(metricName, matchers, labelName)); } // See https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values return this.fetchAPI("".concat(this.labelValuesEndpoint().replace(/:name/gi, labelName), "?").concat(params)).catch(function (error) { if (_this.errorHandler) { _this.errorHandler(error); } return []; }); }; HTTPPrometheusClient.prototype.metricMetadata = function () { var _this = this; return this.fetchAPI(this.metricMetadataEndpoint()).catch(function (error) { if (_this.errorHandler) { _this.errorHandler(error); } return {}; }); }; HTTPPrometheusClient.prototype.series = function (metricName, matchers, labelName) { var _this = this; var params = new URLSearchParams(); if (this.lookbackInterval) { var end = new Date(); var start = new Date(end.getTime() - this.lookbackInterval); params.set('start', start.toISOString()); params.set('end', end.toISOString()); } params.set('match[]', (0, parser_1.labelMatchersToString)(metricName, matchers, labelName)); var request = this.buildRequest(this.seriesEndpoint(), params); // See https://prometheus.io/docs/prometheus/latest/querying/api/#finding-series-by-label-matchers return this.fetchAPI(request.uri, { method: this.httpMethod, body: request.body, }).catch(function (error) { if (_this.errorHandler) { _this.errorHandler(error); } return []; }); }; HTTPPrometheusClient.prototype.metricNames = function () { return this.labelValues('__name__'); }; HTTPPrometheusClient.prototype.flags = function () { var _this = this; return this.fetchAPI(this.flagsEndpoint()).catch(function (error) { if (_this.errorHandler) { _this.errorHandler(error); } return {}; }); }; HTTPPrometheusClient.prototype.destroy = function () { var e_1, _a; try { for (var _b = __values(this.abortControllers), _c = _b.next(); !_c.done; _c = _b.next()) { var controller = _c.value; controller.abort(); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } this.abortControllers.clear(); }; HTTPPrometheusClient.prototype.fetchAPI = function (resource, init) { var _this = this; var controller = new AbortController(); this.abortControllers.add(controller); if (init) { init.headers = this.requestHeaders; init.signal = controller.signal; } else { init = { headers: this.requestHeaders, signal: controller.signal }; } return this.fetchFn(this.url + resource, init) .then(function (res) { if (!res.ok && ![badRequest, unprocessableEntity, serviceUnavailable].includes(res.status)) { throw new Error(res.statusText); } return res; }) .then(function (res) { return res.json(); }) .then(function (apiRes) { if (apiRes.status === 'error') { throw new Error(apiRes.error !== undefined ? apiRes.error : 'missing "error" field in response JSON'); } if (apiRes.data === undefined) { throw new Error('missing "data" field in response JSON'); } return apiRes.data; }) .finally(function () { _this.abortControllers.delete(controller); }); }; HTTPPrometheusClient.prototype.buildRequest = function (endpoint, params) { var uri = endpoint; var body = params; if (this.httpMethod === 'GET') { uri = "".concat(uri, "?").concat(params); body = null; } return { uri: uri, body: body }; }; HTTPPrometheusClient.prototype.labelsEndpoint = function () { return "".concat(this.apiPrefix, "/labels"); }; HTTPPrometheusClient.prototype.labelValuesEndpoint = function () { return "".concat(this.apiPrefix, "/label/:name/values"); }; HTTPPrometheusClient.prototype.seriesEndpoint = function () { return "".concat(this.apiPrefix, "/series"); }; HTTPPrometheusClient.prototype.metricMetadataEndpoint = function () { return "".concat(this.apiPrefix, "/metadata"); }; HTTPPrometheusClient.prototype.flagsEndpoint = function () { return "".concat(this.apiPrefix, "/status/flags"); }; return HTTPPrometheusClient; }()); exports.HTTPPrometheusClient = HTTPPrometheusClient; var Cache = /** @class */ (function () { function Cache(config) { var maxAge = { ttl: config && config.maxAge ? config.maxAge : 5 * 60 * 1000, ttlAutopurge: true, }; this.completeAssociation = new lru_cache_1.LRUCache(maxAge); this.metricMetadata = {}; this.labelValues = new lru_cache_1.LRUCache(maxAge); this.labelNames = []; this.flags = {}; if (config === null || config === void 0 ? void 0 : config.initialMetricList) { this.setLabelValues('__name__', config.initialMetricList); } } Cache.prototype.getAssociations = function (metricName) { var currentAssociation = this.completeAssociation.get(metricName); if (!currentAssociation) { currentAssociation = new Map(); this.completeAssociation.set(metricName, currentAssociation); } return currentAssociation; }; Cache.prototype.setAssociations = function (metricName, series) { var _this = this; series.forEach(function (labelSet) { var e_2, _a; var currentAssociation = _this.getAssociations(metricName); try { for (var _b = __values(Object.entries(labelSet)), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), key = _d[0], value = _d[1]; if (key === '__name__') { continue; } var labelValues = currentAssociation.get(key); if (labelValues === undefined) { currentAssociation.set(key, new Set([value])); } else { labelValues.add(value); } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_2) throw e_2.error; } } }); }; Cache.prototype.setLabelValuesAssociation = function (metricName, labelName, labelValues) { var currentAssociation = this.getAssociations(metricName); var set = currentAssociation.get(labelName); if (set === undefined) { currentAssociation.set(labelName, new Set(labelValues)); } else { labelValues.forEach(function (value) { set.add(value); }); } }; Cache.prototype.setLabelNamesAssociation = function (metricName, labelNames) { var currentAssociation = this.getAssociations(metricName); labelNames.forEach(function (labelName) { if (labelName === '__name__') { return; } if (!currentAssociation.has(labelName)) { currentAssociation.set(labelName, new Set()); } }); }; Cache.prototype.setFlags = function (flags) { this.flags = flags; }; Cache.prototype.getFlags = function () { return this.flags; }; Cache.prototype.setMetricMetadata = function (metadata) { this.metricMetadata = metadata; }; Cache.prototype.getMetricMetadata = function () { return this.metricMetadata; }; Cache.prototype.setLabelNames = function (labelNames, metricName) { if (metricName && metricName.length > 0) { this.setLabelNamesAssociation(metricName, labelNames); } this.labelNames = labelNames; }; Cache.prototype.getLabelNames = function (metricName) { if (!metricName || metricName.length === 0) { return this.labelNames; } var labelSet = this.completeAssociation.get(metricName); return labelSet ? Array.from(labelSet.keys()) : []; }; Cache.prototype.setLabelValues = function (labelName, labelValues, metricName) { if (metricName && metricName.length > 0) { this.setLabelValuesAssociation(metricName, labelName, labelValues); } this.labelValues.set(labelName, labelValues); }; Cache.prototype.getLabelValues = function (labelName, metricName) { if (!metricName || metricName.length === 0) { var result = this.labelValues.get(labelName); return result ? result : []; } var labelSet = this.completeAssociation.get(metricName); if (labelSet) { var labelValues = labelSet.get(labelName); return labelValues ? Array.from(labelValues) : []; } return []; }; return Cache; }()); var CachedPrometheusClient = /** @class */ (function () { function CachedPrometheusClient(client, config) { this.client = client; this.cache = new Cache(config); } CachedPrometheusClient.prototype.labelNames = function (metricName) { var _this = this; var cachedLabel = this.cache.getLabelNames(metricName); if (cachedLabel && cachedLabel.length > 0) { return Promise.resolve(cachedLabel); } return this.client.labelNames(metricName).then(function (labelNames) { _this.cache.setLabelNames(labelNames, metricName); return _this.cache.getLabelNames(metricName); }); }; CachedPrometheusClient.prototype.labelValues = function (labelName, metricName) { var _this = this; var cachedLabel = this.cache.getLabelValues(labelName, metricName); if (cachedLabel && cachedLabel.length > 0) { return Promise.resolve(cachedLabel); } return this.client.labelValues(labelName, metricName).then(function (labelValues) { _this.cache.setLabelValues(labelName, labelValues, metricName); return labelValues; }); }; CachedPrometheusClient.prototype.metricMetadata = function () { var _this = this; var cachedMetadata = this.cache.getMetricMetadata(); if (cachedMetadata && Object.keys(cachedMetadata).length > 0) { return Promise.resolve(cachedMetadata); } return this.client.metricMetadata().then(function (metadata) { _this.cache.setMetricMetadata(metadata); return metadata; }); }; CachedPrometheusClient.prototype.series = function (metricName) { var _this = this; return this.client.series(metricName).then(function (series) { _this.cache.setAssociations(metricName, series); return series; }); }; CachedPrometheusClient.prototype.metricNames = function () { return this.labelValues('__name__'); }; CachedPrometheusClient.prototype.flags = function () { var _this = this; var cachedFlags = this.cache.getFlags(); if (cachedFlags && Object.keys(cachedFlags).length > 0) { return Promise.resolve(cachedFlags); } return this.client.flags().then(function (flags) { _this.cache.setFlags(flags); return flags; }); }; CachedPrometheusClient.prototype.destroy = function () { var _a, _b; (_b = (_a = this.client).destroy) === null || _b === void 0 ? void 0 : _b.call(_a); }; return CachedPrometheusClient; }()); exports.CachedPrometheusClient = CachedPrometheusClient; //# sourceMappingURL=prometheus.js.map