From fb96cf45ce5f2da6c9a2fb98955e851b735d9881 Mon Sep 17 00:00:00 2001 From: rozetko Date: Thu, 23 Aug 2018 16:50:04 +0300 Subject: [PATCH] Get all data from Grafana's datasource by chunks (#111) --- server/src/services/grafana_service.ts | 67 ++++++++++++++++++++------ 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/server/src/services/grafana_service.ts b/server/src/services/grafana_service.ts index c736ef4..fd97218 100644 --- a/server/src/services/grafana_service.ts +++ b/server/src/services/grafana_service.ts @@ -3,9 +3,10 @@ import { Metric } from '../models/metric_model'; import { HASTIC_API_KEY } from '../config'; import { URL } from 'url'; -import { stringify } from 'querystring'; import axios from 'axios'; - + + +const CHUNK_SIZE = 50000; export type Timestamp = number; /** @@ -15,25 +16,63 @@ export type Timestamp = number; export async function queryByMetric(metric: Metric, panelUrl: string): Promise<[number, number][]> { let datasource = metric.datasource; - if(datasource.type !== 'influxdb') { + if (datasource.type !== 'influxdb') { throw new Error(`${datasource.type} queries are not supported yet`); } - var params = {}; + let origin = new URL(panelUrl).origin; - let url = `${origin}/${datasource.url}?${stringify(params)}`; - console.log(url) + let url = `${origin}/${datasource.url}`; + + let params = datasource.params + let records = await getRecordsCount(url, params); + + let limit = Math.min(records, CHUNK_SIZE); + let offset = 0; - let headers = { 'Authorization': 'Bearer ' + HASTIC_API_KEY }; + let data = []; + while (offset <= records) { + let paramsClone = Object.assign({}, params); + paramsClone.q = paramsClone.q.replace(/(WHERE time >[^A-Z]+)/, `LIMIT ${limit} OFFSET ${offset}`); - let res = await axios.get(url, { headers }); + let chunk = await queryGrafana(url, paramsClone); + data = data.concat(chunk); - let results = res.data['results']; - console.log(results) - if(results === undefined) { - throw new Error('reuslts field is undefined in response'); + offset += CHUNK_SIZE; } - if(results.series === undefined) { + + return data; +} + +async function getRecordsCount(url: string, params: any) { + let paramsClone = Object.assign({}, params); + let query = paramsClone.q; + + let field = query.match(/"(\w+)"\)*\sFROM/)[1]; + let measurement = query.match(/FROM\s"(\w+)"/)[1]; + paramsClone.q = `SELECT COUNT(${field}) FROM ${measurement}`; + let result = await queryGrafana(url, paramsClone); + return result[0][1]; +} + +async function queryGrafana(url: string, params: any) { + let headers = { Authorization: `Bearer ${HASTIC_API_KEY}` }; + + let res; + try { + res = await axios.get(url, { params, headers }); + } catch (e) { + console.error(`Error while getting data from Grafana: ${e}`); + } + + if (res.data.results === undefined) { + throw new Error('results field is undefined in response'); + } + + // TODO: support more than 1 metric (each res.data.results item is a metric) + let results = res.data.results[0]; + if (results.series === undefined) { return []; } - return res['series'][0]; + + return results.series[0].values; }