Files
grafana-zabbix/src/datasource-zabbix/zabbix/connectors/sql/sqlConnector.js
Tommi Palomäki 1ae4b86ca9 Fix to consolidate avg accuracy (#753)
* The interval must fit exactly n times to the time range and query made so that the resulting avg will be exact

* Add interval fix also to trend query
2020-05-15 14:08:12 +03:00

128 lines
4.1 KiB
JavaScript

import _ from 'lodash';
import { getBackendSrv } from '@grafana/runtime';
import { compactQuery } from '../../../utils';
import mysql from './mysql';
import postgres from './postgres';
import dbConnector, { DBConnector, DEFAULT_QUERY_LIMIT, HISTORY_TO_TABLE_MAP, TREND_TO_TABLE_MAP } from '../dbConnector';
const supportedDatabases = {
mysql: 'mysql',
postgres: 'postgres'
};
export class SQLConnector extends DBConnector {
constructor(options) {
super(options);
this.limit = options.limit || DEFAULT_QUERY_LIMIT;
this.sqlDialect = null;
super.loadDBDataSource()
.then(() => {
this.loadSQLDialect();
});
}
loadSQLDialect() {
if (this.datasourceTypeId === supportedDatabases.postgres) {
this.sqlDialect = postgres;
} else {
this.sqlDialect = mysql;
}
}
/**
* Try to invoke test query for one of Zabbix database tables.
*/
testDataSource() {
let testQuery = this.sqlDialect.testQuery();
return this.invokeSQLQuery(testQuery);
}
getHistory(items, timeFrom, timeTill, options) {
let {intervalMs, consolidateBy} = options;
let intervalSec = Math.ceil(intervalMs / 1000);
// The interval must match the time range exactly n times, otherwise
// the resulting first and last data points will yield invalid values in the
// calculated average value in downsampleSeries - when using consolidateBy(avg)
let numOfIntervals = Math.ceil((timeTill - timeFrom) / intervalSec);
intervalSec = (timeTill - timeFrom) / numOfIntervals;
consolidateBy = consolidateBy || 'avg';
let aggFunction = dbConnector.consolidateByFunc[consolidateBy];
// Group items by value type and perform request for each value type
let grouped_items = _.groupBy(items, 'value_type');
let promises = _.map(grouped_items, (items, value_type) => {
let itemids = _.map(items, 'itemid').join(', ');
let table = HISTORY_TO_TABLE_MAP[value_type];
let query = this.sqlDialect.historyQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction);
query = compactQuery(query);
return this.invokeSQLQuery(query);
});
return Promise.all(promises).then(results => {
return _.flatten(results);
});
}
getTrends(items, timeFrom, timeTill, options) {
let { intervalMs, consolidateBy } = options;
let intervalSec = Math.ceil(intervalMs / 1000);
// The interval must match the time range exactly n times, otherwise
// the resulting first and last data points will yield invalid values in the
// calculated average value in downsampleSeries - when using consolidateBy(avg)
let numOfIntervals = Math.ceil((timeTill - timeFrom) / intervalSec);
intervalSec = (timeTill - timeFrom) / numOfIntervals;
consolidateBy = consolidateBy || 'avg';
let aggFunction = dbConnector.consolidateByFunc[consolidateBy];
// Group items by value type and perform request for each value type
let grouped_items = _.groupBy(items, 'value_type');
let promises = _.map(grouped_items, (items, value_type) => {
let itemids = _.map(items, 'itemid').join(', ');
let table = TREND_TO_TABLE_MAP[value_type];
let valueColumn = _.includes(['avg', 'min', 'max', 'sum'], consolidateBy) ? consolidateBy : 'avg';
valueColumn = dbConnector.consolidateByTrendColumns[valueColumn];
let query = this.sqlDialect.trendsQuery(itemids, table, timeFrom, timeTill, intervalSec, aggFunction, valueColumn);
query = compactQuery(query);
return this.invokeSQLQuery(query);
});
return Promise.all(promises).then(results => {
return _.flatten(results);
});
}
invokeSQLQuery(query) {
let queryDef = {
refId: 'A',
format: 'time_series',
datasourceId: this.datasourceId,
rawSql: query,
maxDataPoints: this.limit
};
return getBackendSrv().datasourceRequest({
url: '/api/tsdb/query',
method: 'POST',
data: {
queries: [queryDef],
}
})
.then(response => {
let results = response.data.results;
if (results['A']) {
return results['A'].series;
} else {
return null;
}
});
}
}