The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/core/services/backend_srv.ts

216 lines
5.6 KiB

///<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, private contextSrv) {
}
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.match(/^http/);
var firstAttempt = options.retry === 0;
if (requestIsLocal) {
if (this.contextSrv.user && this.contextSrv.user.orgId) {
options.headers = options.headers || {};
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId;
}
if (options.url.indexOf("/") === 0) {
options.url = options.url.substring(1);
}
}
return this.$http(options).then(results => {
if (options.method !== 'GET') {
if (results && results.data.message) {
if (options.showSuccessAlert !== false) {
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, err), 50);
throw err;
});
}
addCanceler(requestId, canceler) {
if (requestId in this.inFlightRequests) {
this.inFlightRequests[requestId].push(canceler);
} else {
this.inFlightRequests[requestId] = [canceler];
}
}
resolveCancelerIfExists(requestId) {
var cancelers = this.inFlightRequests[requestId];
if (!_.isUndefined(cancelers) && cancelers.length) {
cancelers[0].resolve();
}
}
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 requestId = options.requestId;
if (requestId) {
this.resolveCancelerIfExists(requestId);
// create new canceler
var canceler = this.$q.defer();
options.timeout = canceler.promise;
this.addCanceler(requestId, canceler);
}
var requestIsLocal = !options.url.match(/^http/);
var firstAttempt = options.retry === 0;
if (requestIsLocal) {
if (this.contextSrv.user && this.contextSrv.user.orgId) {
options.headers = options.headers || {};
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId;
}
if (options.url.indexOf("/") === 0) {
options.url = options.url.substring(1);
}
if (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,
response: err.data,
};
}
// for Prometheus
if (!err.data.message && _.isString(err.data.error)) {
err.data.message = err.data.error;
}
throw err;
}).finally(() => {
// clean up
if (options.requestId) {
this.inFlightRequests[options.requestId].shift();
}
});
}
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,
parentId: dash.parentId,
overwrite: options.overwrite === true,
message: options.message || '',
});
}
}
coreModule.service('backendSrv', BackendSrv);