mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(datasource): cancel in flight data source requests, refeatoring #5321
This commit is contained in:
parent
6d3521c240
commit
81e9aa4de4
@ -63,6 +63,8 @@ func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *ht
|
|||||||
req.Header.Add("Authorization", dsAuth)
|
req.Header.Add("Authorization", dsAuth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
|
||||||
// clear cookie headers
|
// clear cookie headers
|
||||||
req.Header.Del("Cookie")
|
req.Header.Del("Cookie")
|
||||||
req.Header.Del("Set-Cookie")
|
req.Header.Del("Set-Cookie")
|
||||||
|
@ -1,175 +0,0 @@
|
|||||||
define([
|
|
||||||
'angular',
|
|
||||||
'lodash',
|
|
||||||
'../core_module',
|
|
||||||
'app/core/config',
|
|
||||||
],
|
|
||||||
function (angular, _, coreModule, config) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
coreModule.default.service('backendSrv', function($http, alertSrv, $timeout, $q) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.get = function(url, params) {
|
|
||||||
return this.request({ method: 'GET', url: url, params: params });
|
|
||||||
};
|
|
||||||
|
|
||||||
this.delete = function(url) {
|
|
||||||
return this.request({ method: 'DELETE', url: url });
|
|
||||||
};
|
|
||||||
|
|
||||||
this.post = function(url, data) {
|
|
||||||
return this.request({ method: 'POST', url: url, data: data });
|
|
||||||
};
|
|
||||||
|
|
||||||
this.patch = function(url, data) {
|
|
||||||
return this.request({ method: 'PATCH', url: url, data: data });
|
|
||||||
};
|
|
||||||
|
|
||||||
this.put = function(url, data) {
|
|
||||||
return this.request({ method: 'PUT', url: url, data: data });
|
|
||||||
};
|
|
||||||
|
|
||||||
this._handleError = function(err) {
|
|
||||||
return function() {
|
|
||||||
if (err.isHandled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = err.data || { message: 'Unexpected error' };
|
|
||||||
if (_.isString(data)) {
|
|
||||||
data = { message: data };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err.status === 422) {
|
|
||||||
alertSrv.set("Validation failed", data.message, "warning", 4000);
|
|
||||||
throw data;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.severity = 'error';
|
|
||||||
|
|
||||||
if (err.status < 500) {
|
|
||||||
data.severity = "warning";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.message) {
|
|
||||||
alertSrv.set("Problem!", data.message, data.severity, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw data;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
this.request = function(options) {
|
|
||||||
options.retry = options.retry || 0;
|
|
||||||
var requestIsLocal = options.url.indexOf('/') === 0;
|
|
||||||
var firstAttempt = options.retry === 0;
|
|
||||||
|
|
||||||
if (requestIsLocal && !options.hasSubUrl) {
|
|
||||||
options.url = config.appSubUrl + options.url;
|
|
||||||
options.hasSubUrl = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $http(options).then(function(results) {
|
|
||||||
if (options.method !== 'GET') {
|
|
||||||
if (results && results.data.message) {
|
|
||||||
alertSrv.set(results.data.message, '', 'success', 3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return results.data;
|
|
||||||
}, function(err) {
|
|
||||||
// handle unauthorized
|
|
||||||
if (err.status === 401 && firstAttempt) {
|
|
||||||
return self.loginPing().then(function() {
|
|
||||||
options.retry = 1;
|
|
||||||
return self.request(options);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$timeout(self._handleError(err), 50);
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var datasourceInFlightRequests = {};
|
|
||||||
var HTTP_REQUEST_ABORTED = -1;
|
|
||||||
this.datasourceRequest = function(options) {
|
|
||||||
options.retry = options.retry || 0;
|
|
||||||
|
|
||||||
// A requestID is provided by the datasource as a unique identifier for a
|
|
||||||
// particular query. If the requestID exists, the promise it is keyed to
|
|
||||||
// is canceled, canceling the previous datasource request if it is still
|
|
||||||
// in-flight.
|
|
||||||
var canceler;
|
|
||||||
if (options.requestID) {
|
|
||||||
if (canceler = datasourceInFlightRequests[options.requestID]) {
|
|
||||||
canceler.resolve();
|
|
||||||
}
|
|
||||||
canceler = $q.defer();
|
|
||||||
options.timeout = canceler.promise;
|
|
||||||
datasourceInFlightRequests[options.requestID] = canceler;
|
|
||||||
}
|
|
||||||
|
|
||||||
var requestIsLocal = options.url.indexOf('/') === 0;
|
|
||||||
var firstAttempt = options.retry === 0;
|
|
||||||
|
|
||||||
if (requestIsLocal && options.headers && options.headers.Authorization) {
|
|
||||||
options.headers['X-DS-Authorization'] = options.headers.Authorization;
|
|
||||||
delete options.headers.Authorization;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $http(options).then(null, function(err) {
|
|
||||||
if (err.status === HTTP_REQUEST_ABORTED) {
|
|
||||||
// TODO: Hitting refresh before the original request returns cancels
|
|
||||||
// the "loading" animation on the panes, but it should continue to be
|
|
||||||
// visible.
|
|
||||||
err.statusText = "request aborted";
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle unauthorized for backend requests
|
|
||||||
if (requestIsLocal && firstAttempt && err.status === 401) {
|
|
||||||
return self.loginPing().then(function() {
|
|
||||||
options.retry = 1;
|
|
||||||
if (canceler) {
|
|
||||||
canceler.resolve();
|
|
||||||
}
|
|
||||||
return self.datasourceRequest(options);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//populate error obj on Internal Error
|
|
||||||
if (_.isString(err.data) && err.status === 500) {
|
|
||||||
err.data = {
|
|
||||||
error: err.statusText
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// for Prometheus
|
|
||||||
if (!err.data.message && _.isString(err.data.error)) {
|
|
||||||
err.data.message = err.data.error;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.loginPing = function() {
|
|
||||||
return this.request({url: '/api/login/ping', method: 'GET', retry: 1 });
|
|
||||||
};
|
|
||||||
|
|
||||||
this.search = function(query) {
|
|
||||||
return this.get('/api/search', query);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.getDashboard = function(type, slug) {
|
|
||||||
return this.get('/api/dashboards/' + type + '/' + slug);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.saveDashboard = function(dash, options) {
|
|
||||||
options = (options || {});
|
|
||||||
return this.post('/api/dashboards/db/', {dashboard: dash, overwrite: options.overwrite === true});
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
177
public/app/core/services/backend_srv.ts
Normal file
177
public/app/core/services/backend_srv.ts
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
///<reference path="../../headers/common.d.ts" />
|
||||||
|
|
||||||
|
import angular from 'angular';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import config from 'app/core/config';
|
||||||
|
import coreModule from 'app/core/core_module';
|
||||||
|
|
||||||
|
export class BackendSrv {
|
||||||
|
inFlightRequests = {};
|
||||||
|
HTTP_REQUEST_CANCELLED = -1;
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
constructor(private $http, private alertSrv, private $rootScope, private $q, private $timeout) {
|
||||||
|
}
|
||||||
|
|
||||||
|
get(url, params?) {
|
||||||
|
return this.request({ method: 'GET', url: url, params: params });
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(url) {
|
||||||
|
return this.request({ method: 'DELETE', url: url });
|
||||||
|
}
|
||||||
|
|
||||||
|
post(url, data) {
|
||||||
|
return this.request({ method: 'POST', url: url, data: data });
|
||||||
|
};
|
||||||
|
|
||||||
|
patch(url, data) {
|
||||||
|
return this.request({ method: 'PATCH', url: url, data: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
put(url, data) {
|
||||||
|
return this.request({ method: 'PUT', url: url, data: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
requestErrorHandler(err) {
|
||||||
|
if (err.isHandled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = err.data || { message: 'Unexpected error' };
|
||||||
|
if (_.isString(data)) {
|
||||||
|
data = { message: data };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.status === 422) {
|
||||||
|
this.alertSrv.set("Validation failed", data.message, "warning", 4000);
|
||||||
|
throw data;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.severity = 'error';
|
||||||
|
|
||||||
|
if (err.status < 500) {
|
||||||
|
data.severity = "warning";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.message) {
|
||||||
|
this.alertSrv.set("Problem!", data.message, data.severity, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw data;
|
||||||
|
}
|
||||||
|
|
||||||
|
request(options) {
|
||||||
|
options.retry = options.retry || 0;
|
||||||
|
var requestIsLocal = options.url.indexOf('/') === 0;
|
||||||
|
var firstAttempt = options.retry === 0;
|
||||||
|
|
||||||
|
if (requestIsLocal && !options.hasSubUrl) {
|
||||||
|
options.url = config.appSubUrl + options.url;
|
||||||
|
options.hasSubUrl = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.$http(options).then(results => {
|
||||||
|
if (options.method !== 'GET') {
|
||||||
|
if (results && results.data.message) {
|
||||||
|
this.alertSrv.set(results.data.message, '', 'success', 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results.data;
|
||||||
|
}, err => {
|
||||||
|
// handle unauthorized
|
||||||
|
if (err.status === 401 && firstAttempt) {
|
||||||
|
return this.loginPing().then(() => {
|
||||||
|
options.retry = 1;
|
||||||
|
return this.request(options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$timeout(this.requestErrorHandler.bind(this), 50);
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
datasourceRequest(options) {
|
||||||
|
options.retry = options.retry || 0;
|
||||||
|
|
||||||
|
// A requestID is provided by the datasource as a unique identifier for a
|
||||||
|
// particular query. If the requestID exists, the promise it is keyed to
|
||||||
|
// is canceled, canceling the previous datasource request if it is still
|
||||||
|
// in-flight.
|
||||||
|
var canceler;
|
||||||
|
if (options.requestId) {
|
||||||
|
canceler = this.inFlightRequests[options.requestId];
|
||||||
|
if (canceler) {
|
||||||
|
canceler.resolve();
|
||||||
|
}
|
||||||
|
// create new canceler
|
||||||
|
canceler = this.$q.defer();
|
||||||
|
options.timeout = canceler.promise;
|
||||||
|
this.inFlightRequests[options.requestId] = canceler;
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestIsLocal = options.url.indexOf('/') === 0;
|
||||||
|
var firstAttempt = options.retry === 0;
|
||||||
|
|
||||||
|
if (requestIsLocal && options.headers && options.headers.Authorization) {
|
||||||
|
options.headers['X-DS-Authorization'] = options.headers.Authorization;
|
||||||
|
delete options.headers.Authorization;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.$http(options).catch(err => {
|
||||||
|
if (err.status === this.HTTP_REQUEST_CANCELLED) {
|
||||||
|
throw {err, cancelled: true};
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle unauthorized for backend requests
|
||||||
|
if (requestIsLocal && firstAttempt && err.status === 401) {
|
||||||
|
return this.loginPing().then(() => {
|
||||||
|
options.retry = 1;
|
||||||
|
if (canceler) {
|
||||||
|
canceler.resolve();
|
||||||
|
}
|
||||||
|
return this.datasourceRequest(options);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//populate error obj on Internal Error
|
||||||
|
if (_.isString(err.data) && err.status === 500) {
|
||||||
|
err.data = {
|
||||||
|
error: err.statusText
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// for Prometheus
|
||||||
|
if (!err.data.message && _.isString(err.data.error)) {
|
||||||
|
err.data.message = err.data.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}).finally(() => {
|
||||||
|
// clean up
|
||||||
|
if (options.requestId) {
|
||||||
|
delete this.inFlightRequests[options.requestId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loginPing() {
|
||||||
|
return this.request({url: '/api/login/ping', method: 'GET', retry: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
search(query) {
|
||||||
|
return this.get('/api/search', query);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDashboard(type, slug) {
|
||||||
|
return this.get('/api/dashboards/' + type + '/' + slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveDashboard(dash, options) {
|
||||||
|
options = (options || {});
|
||||||
|
return this.post('/api/dashboards/db/', {dashboard: dash, overwrite: options.overwrite === true});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
coreModule.service('backendSrv', BackendSrv);
|
@ -12,7 +12,7 @@ import * as dateMath from 'app/core/utils/datemath';
|
|||||||
import {Subject} from 'vendor/npm/rxjs/Subject';
|
import {Subject} from 'vendor/npm/rxjs/Subject';
|
||||||
|
|
||||||
class MetricsPanelCtrl extends PanelCtrl {
|
class MetricsPanelCtrl extends PanelCtrl {
|
||||||
error: boolean;
|
error: any;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
datasource: any;
|
datasource: any;
|
||||||
datasourceName: any;
|
datasourceName: any;
|
||||||
@ -86,8 +86,14 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
.then(this.issueQueries.bind(this))
|
.then(this.issueQueries.bind(this))
|
||||||
.then(this.handleQueryResult.bind(this))
|
.then(this.handleQueryResult.bind(this))
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
// if cancelled keep loading set to true
|
||||||
|
if (err.cancelled) {
|
||||||
|
console.log('Panel request cancelled', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.error = err.message || "Timeseries data request error";
|
this.error = err.message || "Request Error";
|
||||||
this.inspector = {error: err};
|
this.inspector = {error: err};
|
||||||
this.events.emit('data-error', err);
|
this.events.emit('data-error', err);
|
||||||
console.log('Panel data error:', err);
|
console.log('Panel data error:', err);
|
||||||
@ -182,10 +188,6 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
cacheTimeout: this.panel.cacheTimeout
|
cacheTimeout: this.panel.cacheTimeout
|
||||||
};
|
};
|
||||||
|
|
||||||
metricsQuery.targets.forEach(function(target) {
|
|
||||||
target.exprID = target.refId + metricsQuery.panelId;
|
|
||||||
});
|
|
||||||
|
|
||||||
return datasource.query(metricsQuery);
|
return datasource.query(metricsQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,13 +30,17 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
return $q.when({data: []});
|
return $q.when({data: []});
|
||||||
}
|
}
|
||||||
|
|
||||||
var httpOptions: any = {method: this.render_method, url: '/render'};
|
var httpOptions: any = {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/render',
|
||||||
|
data: params.join('&'),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
if (httpOptions.method === 'GET') {
|
if (options.panelId) {
|
||||||
httpOptions.url = httpOptions.url + '?' + params.join('&');
|
httpOptions.requestId = 'panel' + options.panelId;
|
||||||
} else {
|
|
||||||
httpOptions.data = params.join('&');
|
|
||||||
httpOptions.headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.doGraphiteRequest(httpOptions).then(this.convertDataPointsToMs);
|
return this.doGraphiteRequest(httpOptions).then(this.convertDataPointsToMs);
|
||||||
@ -177,17 +181,6 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.listDashboards = function(query) {
|
|
||||||
return this.doGraphiteRequest({ method: 'GET', url: '/dashboard/find/', params: {query: query || ''} })
|
|
||||||
.then(function(results) {
|
|
||||||
return results.data.dashboards;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.loadDashboard = function(dashName) {
|
|
||||||
return this.doGraphiteRequest({method: 'GET', url: '/dashboard/load/' + encodeURIComponent(dashName) });
|
|
||||||
};
|
|
||||||
|
|
||||||
this.doGraphiteRequest = function(options) {
|
this.doGraphiteRequest = function(options) {
|
||||||
if (this.basicAuth || this.withCredentials) {
|
if (this.basicAuth || this.withCredentials) {
|
||||||
options.withCredentials = true;
|
options.withCredentials = true;
|
||||||
@ -198,7 +191,7 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
}
|
}
|
||||||
|
|
||||||
options.url = this.url + options.url;
|
options.url = this.url + options.url;
|
||||||
options.inspect = { type: 'graphite' };
|
options.inspect = {type: 'graphite'};
|
||||||
|
|
||||||
return backendSrv.datasourceRequest(options);
|
return backendSrv.datasourceRequest(options);
|
||||||
};
|
};
|
||||||
|
@ -21,11 +21,11 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
this.withCredentials = instanceSettings.withCredentials;
|
this.withCredentials = instanceSettings.withCredentials;
|
||||||
this.lastErrors = {};
|
this.lastErrors = {};
|
||||||
|
|
||||||
this._request = function(method, url, requestID) {
|
this._request = function(method, url, requestId) {
|
||||||
var options: any = {
|
var options: any = {
|
||||||
url: this.url + url,
|
url: this.url + url,
|
||||||
method: method,
|
method: method,
|
||||||
requestID: requestID,
|
requestId: requestId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.basicAuth || this.withCredentials) {
|
if (this.basicAuth || this.withCredentials) {
|
||||||
@ -77,7 +77,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
|
|
||||||
var query: any = {};
|
var query: any = {};
|
||||||
query.expr = templateSrv.replace(target.expr, options.scopedVars, self.interpolateQueryExpr);
|
query.expr = templateSrv.replace(target.expr, options.scopedVars, self.interpolateQueryExpr);
|
||||||
query.requestID = target.exprID;
|
query.requestId = target.expr;
|
||||||
|
|
||||||
var interval = target.interval || options.interval;
|
var interval = target.interval || options.interval;
|
||||||
var intervalFactor = target.intervalFactor || 1;
|
var intervalFactor = target.intervalFactor || 1;
|
||||||
@ -103,14 +103,10 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
return this.performTimeSeriesQuery(query, start, end);
|
return this.performTimeSeriesQuery(query, start, end);
|
||||||
}, this));
|
}, this));
|
||||||
|
|
||||||
return $q.all(allQueryPromise)
|
return $q.all(allQueryPromise).then(function(allResponse) {
|
||||||
.then(function(allResponse) {
|
|
||||||
var result = [];
|
var result = [];
|
||||||
|
|
||||||
_.each(allResponse, function(response, index) {
|
_.each(allResponse, function(response, index) {
|
||||||
if (response.status === HTTP_REQUEST_ABORTED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (response.status === 'error') {
|
if (response.status === 'error') {
|
||||||
self.lastErrors.query = response.error;
|
self.lastErrors.query = response.error;
|
||||||
throw response.error;
|
throw response.error;
|
||||||
@ -128,7 +124,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
|
|
||||||
this.performTimeSeriesQuery = function(query, start, end) {
|
this.performTimeSeriesQuery = function(query, start, end) {
|
||||||
var url = '/api/v1/query_range?query=' + encodeURIComponent(query.expr) + '&start=' + start + '&end=' + end + '&step=' + query.step;
|
var url = '/api/v1/query_range?query=' + encodeURIComponent(query.expr) + '&start=' + start + '&end=' + end + '&step=' + query.step;
|
||||||
return this._request('GET', url, query.requestID);
|
return this._request('GET', url, query.requestId);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.performSuggestQuery = function(query) {
|
this.performSuggestQuery = function(query) {
|
||||||
@ -175,9 +171,11 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
expr: interpolated,
|
expr: interpolated,
|
||||||
step: '60s'
|
step: '60s'
|
||||||
};
|
};
|
||||||
|
|
||||||
var start = getPrometheusTime(options.range.from, false);
|
var start = getPrometheusTime(options.range.from, false);
|
||||||
var end = getPrometheusTime(options.range.to, true);
|
var end = getPrometheusTime(options.range.to, true);
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
return this.performTimeSeriesQuery(query, start, end).then(function(results) {
|
return this.performTimeSeriesQuery(query, start, end).then(function(results) {
|
||||||
var eventList = [];
|
var eventList = [];
|
||||||
tagKeys = tagKeys.split(',');
|
tagKeys = tagKeys.split(',');
|
||||||
|
Loading…
Reference in New Issue
Block a user