import { Datasource, DatasourceQuery } from '../connectors'; import { TsdbKitError, DatasourceUnavailable } from '../types'; import axios from 'axios'; import * as _ from 'lodash'; export class GrafanaUnavailable extends TsdbKitError { }; // TODO: move to class and inherit from QueryService abstract class export async function queryGrafana(query: DatasourceQuery, apiKey: string, datasource: Datasource) { let headers = { Authorization: `Bearer ${apiKey}` }; const grafanaUrl = getGrafanaUrl(query.url); query.url = `${grafanaUrl}/${query.url}`; if(query.headers !== undefined) { _.merge(headers, query.headers); } let axiosQuery = { headers, url: query.url, method: query.method, }; _.defaults(axiosQuery, query.schema); try { return axios(axiosQuery); } catch (e) { // TODO: seems like this error handler can be used for both Grafana and Direct queries const msg = `TSDB-kit: fail while request data: ${e.message}`; const parsedUrl = new URL(query.url); const queryUrl = `query url: ${JSON.stringify(parsedUrl.pathname)}`; console.error(`${msg} ${queryUrl}`); if(e.errno === 'ECONNREFUSED') { throw new GrafanaUnavailable(e.message); } if(e.response !== undefined) { console.error(`Response: \ status: ${e.response.status}, \ response data: ${JSON.stringify(e.response.data)}, \ headers: ${JSON.stringify(e.response.headers)} `); if(e.response.status === 401) { throw new Error(`Unauthorized. Check the API_KEY. ${e.message}`); } if(e.response.status === 502) { let datasourceError = new DatasourceUnavailable( `datasource ${parsedUrl.pathname} unavailable, message: ${e.message}`, datasource.type, query.url ); throw datasourceError; } } throw new Error(msg); } } function getGrafanaUrl(url: string): string { const parsedUrl = new URL(url); const path = parsedUrl.pathname; const panelUrl = path.match(/^\/*([^\/]*)\/d\//); if(panelUrl === null) { return url; } const origin = parsedUrl.origin; const grafanaSubPath = panelUrl[1]; if(grafanaSubPath.length > 0) { return `${origin}/${grafanaSubPath}`; } return origin; }