Use Data frames response format (#1099)

* Use data frames for numeric data

* Use data frames for text data

* Use data frames for IT services

* fix multiple series

* Convert to the wide format if possible

* Fix table format for text data

* Add refId to the data frames

* Align time series from Zabbix API

* Fill gaps with nulls

* Fix moving average functions

* Option for disabling data alignment

* remove unused logging

* Add labels to data frames

* Detect units

* Set min and max for if percent unit used

* Use value mapping from Zabbix

* Rename unitConverter -> convertZabbixUnit

* More units

* Add missing points in front of each series

* Fix handling table data

* fix db connector data frames handling

* fix it services data frames handling

* Detect all known grafana units

* Chore: remove unused logging

* Fix problems format

* Debug logging: show original units

* Add global option for disabling data alignment

* Add tooltip for the disableDataAlignment feature

* Add note about query options

* Functions for aligning timeseries on the backend
This commit is contained in:
Alexander Zobnin
2020-12-22 15:33:14 +03:00
committed by GitHub
parent ad378a81e1
commit 83618178f0
18 changed files with 700 additions and 91 deletions

View File

@@ -3,6 +3,7 @@ import moment from 'moment';
import kbn from 'grafana/app/core/utils/kbn';
import * as c from './constants';
import { VariableQuery, VariableQueryTypes } from './types';
import { arrowTableToDataFrame, isTableData, MappingType, ValueMap, ValueMapping, getValueFormats, DataFrame, FieldType } from '@grafana/data';
/*
* This regex matches 3 types of variable reference with an optional format specifier
@@ -235,6 +236,26 @@ export function escapeRegex(value) {
return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
}
/**
* Parses Zabbix item update interval. Returns 0 in case of custom intervals.
*/
export function parseItemInterval(interval: string): number {
const normalizedInterval = normalizeZabbixInterval(interval);
if (normalizedInterval) {
return parseInterval(normalizedInterval);
}
return 0;
}
export function normalizeZabbixInterval(interval: string): string {
const intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)?/g;
const parsedInterval = intervalPattern.exec(interval);
if (!parsedInterval) {
return '';
}
return parsedInterval[1] + (parsedInterval.length > 2 ? parsedInterval[2] : 's');
}
export function parseInterval(interval: string): number {
const intervalPattern = /(^[\d]+)(y|M|w|d|h|m|s)/g;
const momentInterval: any[] = intervalPattern.exec(interval);
@@ -387,3 +408,65 @@ export function parseTags(tagStr: string): any[] {
export function mustArray(result: any): any[] {
return result || [];
}
const getUnitsMap = () => ({
'%': 'percent',
'b': 'decbits', // bits(SI)
'bps': 'bps', // bits/sec(SI)
'B': 'bytes', // bytes(IEC)
'Bps': 'binBps', // bytes/sec(IEC)
// 'unixtime': 'dateTimeAsSystem',
'uptime': 'dtdhms',
'qps': 'qps', // requests/sec (rps)
'iops': 'iops', // I/O ops/sec (iops)
'Hz': 'hertz', // Hertz (1/s)
'V': 'volt', // Volt (V)
'C': 'celsius', // Celsius (°C)
'RPM': 'rotrpm', // Revolutions per minute (rpm)
'dBm': 'dBm', // Decibel-milliwatt (dBm)
});
const getKnownGrafanaUnits = () => {
const units = {};
const categories = getValueFormats();
for (const category of categories) {
for (const unitDesc of category.submenu) {
const unit = unitDesc.value;
units[unit] = unit;
}
}
return units;
};
const unitsMap = getUnitsMap();
const knownGrafanaUnits = getKnownGrafanaUnits();
export function convertZabbixUnit(zabbixUnit: string): string {
let unit = unitsMap[zabbixUnit];
if (!unit) {
unit = knownGrafanaUnits[zabbixUnit];
}
return unit;
}
export function getValueMapping(item, valueMappings: any[]): ValueMapping[] | null {
const { valuemapid } = item;
const mapping = valueMappings.find(m => m.valuemapid === valuemapid);
if (!mapping) {
return null;
}
return (mapping.mappings as any[]).map((m, i) => {
const valueMapping: ValueMapping = {
id: i,
type: MappingType.ValueToText,
value: m.value,
text: m.newvalue,
};
return valueMapping;
});
}
export function isProblemsDataFrame(data: DataFrame): boolean {
return data.fields.length && data.fields[0].type === FieldType.other && data.fields[0].config.custom['type'] === 'problems';
}