UNPKG

@dash0hq/codemirror-promql

Version:
487 lines 20.7 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"); var hybrid_1 = require("../complete/hybrid"); // 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.lookbackInterval = 60 * 60 * 1000 * 12; //12 hours 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.url = config.url ? config.url : ''; this.errorHandler = config.httpErrorHandler; if (config.lookbackInterval) { 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, matchers) { var _this = this; var end = new Date(); var start = new Date(end.getTime() - this.lookbackInterval); if ((metricName === undefined || metricName === '') && matchers && matchers.length > 0) { // Use series API with empty metric name but include the matchers return this.series('', matchers).then(function (series) { var e_1, _a, e_2, _b; var labelNames = new Set(); // Check if result is empty if (series.length > 0) { try { for (var series_1 = __values(series), series_1_1 = series_1.next(); !series_1_1.done; series_1_1 = series_1.next()) { var labelSet = series_1_1.value; try { for (var _c = (e_2 = void 0, __values(Object.entries(labelSet))), _d = _c.next(); !_d.done; _d = _c.next()) { var _e = __read(_d.value, 1), key = _e[0]; if (hybrid_1.METRIC_NAME_LABELS.includes(key)) { continue; } labelNames.add(key); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_d && !_d.done && (_b = _c.return)) _b.call(_c); } finally { if (e_2) throw e_2.error; } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (series_1_1 && !series_1_1.done && (_a = series_1.return)) _a.call(series_1); } finally { if (e_1) throw e_1.error; } } } // If result is empty just return everything else { return _this.labelNames(''); } return Array.from(labelNames); }); } if (metricName === undefined || metricName === '') { var request = this.buildRequest(this.labelsEndpoint(), new URLSearchParams({ start: start.toISOString(), end: end.toISOString(), })); // 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 []; }); } return this.series(metricName).then(function (series) { var e_3, _a, e_4, _b; var labelNames = new Set(); try { for (var series_2 = __values(series), series_2_1 = series_2.next(); !series_2_1.done; series_2_1 = series_2.next()) { var labelSet = series_2_1.value; try { for (var _c = (e_4 = void 0, __values(Object.entries(labelSet))), _d = _c.next(); !_d.done; _d = _c.next()) { var _e = __read(_d.value, 1), key = _e[0]; if (key === '__name__') { continue; } labelNames.add(key); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (_d && !_d.done && (_b = _c.return)) _b.call(_c); } finally { if (e_4) throw e_4.error; } } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (series_2_1 && !series_2_1.done && (_a = series_2.return)) _a.call(series_2); } finally { if (e_3) throw e_3.error; } } return Array.from(labelNames); }); }; // 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 end = new Date(); var start = new Date(end.getTime() - this.lookbackInterval); if (!metricName || metricName.length === 0) { var params = new URLSearchParams({ start: start.toISOString(), end: end.toISOString(), }); // 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 []; }); } return this.series(metricName, matchers, labelName).then(function (series) { var e_5, _a, e_6, _b; var labelValues = new Set(); try { for (var series_3 = __values(series), series_3_1 = series_3.next(); !series_3_1.done; series_3_1 = series_3.next()) { var labelSet = series_3_1.value; try { for (var _c = (e_6 = void 0, __values(Object.entries(labelSet))), _d = _c.next(); !_d.done; _d = _c.next()) { var _e = __read(_d.value, 2), key = _e[0], value = _e[1]; if (key === '__name__') { continue; } if (key === labelName) { labelValues.add(value); } } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (_d && !_d.done && (_b = _c.return)) _b.call(_c); } finally { if (e_6) throw e_6.error; } } } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (series_3_1 && !series_3_1.done && (_a = series_3.return)) _a.call(series_3); } finally { if (e_5) throw e_5.error; } } return Array.from(labelValues); }); }; 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 end = new Date(); var start = new Date(end.getTime() - this.lookbackInterval); var request = this.buildRequest(this.seriesEndpoint(), new URLSearchParams({ start: start.toISOString(), end: end.toISOString(), 'match[]': (0, parser_1.labelMatchersToString)(metricName, matchers, labelName), })); // 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.fetchAPI = function (resource, init) { if (init) { init.headers = this.requestHeaders; } else { init = { headers: this.requestHeaders }; } 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; }); }; 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.setAssociations = function (metricName, series) { var _this = this; series.forEach(function (labelSet) { var e_7, _a; var currentAssociation = _this.completeAssociation.get(metricName); if (!currentAssociation) { currentAssociation = new Map(); _this.completeAssociation.set(metricName, currentAssociation); } 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_7_1) { e_7 = { error: e_7_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_7) throw e_7.error; } } }); }; 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) { 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) { 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, matchers) { var _this = this; // For the case with matchers, we should bypass cache to ensure accuracy if (matchers && matchers.length > 0) { return this.client.labelNames(metricName, matchers); } var cachedLabel = this.cache.getLabelNames(metricName); if (cachedLabel && cachedLabel.length > 0) { return Promise.resolve(cachedLabel); } if (metricName === undefined || metricName === '') { return this.client.labelNames().then(function (labelNames) { _this.cache.setLabelNames(labelNames); return labelNames; }); } return this.series(metricName).then(function () { 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); } if (metricName === undefined || metricName === '') { return this.client.labelValues(labelName).then(function (labelValues) { _this.cache.setLabelValues(labelName, labelValues); return labelValues; }); } return this.series(metricName).then(function () { return _this.cache.getLabelValues(labelName, metricName); }); }; 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, matchers) { var _this = this; return this.client.series(metricName, matchers).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; }); }; return CachedPrometheusClient; }()); exports.CachedPrometheusClient = CachedPrometheusClient; //# sourceMappingURL=prometheus.js.map