Apply data processing for the IT Service query on the backend
This commit is contained in:
@@ -313,22 +313,7 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
console.log(`Datasource::Performance Query Time (${this.name}): ${queryEnd - queryStart}`);
|
console.log(`Datasource::Performance Query Time (${this.name}): ${queryEnd - queryStart}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const frames = [];
|
return this.handleBackendPostProcessingResponse(result, request, target);
|
||||||
for (const frameJSON of result) {
|
|
||||||
const frame = dataFrameFromJSON(frameJSON);
|
|
||||||
frame.refId = target.refId;
|
|
||||||
frames.push(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
const resp = { data: frames };
|
|
||||||
this.sortByRefId(resp);
|
|
||||||
this.applyFrontendFunctions(resp, request);
|
|
||||||
if (responseHandler.isConvertibleToWide(resp.data)) {
|
|
||||||
console.log('Converting response to the wide format');
|
|
||||||
resp.data = responseHandler.convertToWide(resp.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -345,6 +330,10 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
history = await this.zabbix.getHistoryTS(items, timeRange, options);
|
history = await this.zabbix.getHistoryTS(items, timeRange, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return await this.invokeDataProcessingQuery(history, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
async invokeDataProcessingQuery(timeSeriesData, query) {
|
||||||
// Request backend for data processing
|
// Request backend for data processing
|
||||||
const requestOptions: BackendSrvRequest = {
|
const requestOptions: BackendSrvRequest = {
|
||||||
url: `/api/datasources/${this.datasourceId}/resources/db-connection-post`,
|
url: `/api/datasources/${this.datasourceId}/resources/db-connection-post`,
|
||||||
@@ -354,8 +343,8 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
},
|
},
|
||||||
hideFromInspector: false,
|
hideFromInspector: false,
|
||||||
data: {
|
data: {
|
||||||
query: target,
|
series: timeSeriesData,
|
||||||
series: history,
|
query,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -363,6 +352,25 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleBackendPostProcessingResponse(response, request, target) {
|
||||||
|
const frames = [];
|
||||||
|
for (const frameJSON of response) {
|
||||||
|
const frame = dataFrameFromJSON(frameJSON);
|
||||||
|
frame.refId = target.refId;
|
||||||
|
frames.push(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
const resp = { data: frames };
|
||||||
|
this.sortByRefId(resp);
|
||||||
|
this.applyFrontendFunctions(resp, request);
|
||||||
|
if (responseHandler.isConvertibleToWide(resp.data)) {
|
||||||
|
console.log('Converting response to the wide format');
|
||||||
|
resp.data = responseHandler.convertToWide(resp.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.data;
|
||||||
|
}
|
||||||
|
|
||||||
getTrendValueType(target) {
|
getTrendValueType(target) {
|
||||||
// Find trendValue() function and get specified trend value
|
// Find trendValue() function and get specified trend value
|
||||||
const trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name');
|
const trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name');
|
||||||
@@ -395,62 +403,6 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyDataProcessingFunctions(timeseries_data, target) {
|
|
||||||
const transformFunctions = bindFunctionDefs(target.functions, 'Transform');
|
|
||||||
const aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');
|
|
||||||
const filterFunctions = bindFunctionDefs(target.functions, 'Filter');
|
|
||||||
const aliasFunctions = bindFunctionDefs(target.functions, 'Alias');
|
|
||||||
|
|
||||||
// Apply transformation functions
|
|
||||||
timeseries_data = _.cloneDeep(_.map(timeseries_data, timeseries => {
|
|
||||||
timeseries.datapoints = utils.sequence(transformFunctions)(timeseries.datapoints);
|
|
||||||
return timeseries;
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Apply filter functions
|
|
||||||
if (filterFunctions.length) {
|
|
||||||
timeseries_data = utils.sequence(filterFunctions)(timeseries_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply aggregations
|
|
||||||
if (aggregationFunctions.length) {
|
|
||||||
let dp = _.map(timeseries_data, 'datapoints');
|
|
||||||
dp = utils.sequence(aggregationFunctions)(dp);
|
|
||||||
|
|
||||||
const aggFuncNames = _.map(metricFunctions.getCategories()['Aggregate'], 'name');
|
|
||||||
const lastAgg = _.findLast(target.functions, func => {
|
|
||||||
return _.includes(aggFuncNames, func.def.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
timeseries_data = [{
|
|
||||||
target: lastAgg.text,
|
|
||||||
datapoints: dp
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply alias functions
|
|
||||||
_.forEach(timeseries_data, utils.sequence(aliasFunctions).bind(this));
|
|
||||||
|
|
||||||
// Apply Time-related functions (timeShift(), etc)
|
|
||||||
// Find timeShift() function and get specified trend value
|
|
||||||
this.applyTimeShiftFunction(timeseries_data, target);
|
|
||||||
|
|
||||||
return timeseries_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
applyTimeShiftFunction(timeseries_data, target) {
|
|
||||||
// Find timeShift() function and get specified interval
|
|
||||||
const timeShiftFunc = _.find(target.functions, (func) => {
|
|
||||||
return func.def.name === 'timeShift';
|
|
||||||
});
|
|
||||||
if (timeShiftFunc) {
|
|
||||||
const shift = timeShiftFunc.params[0];
|
|
||||||
_.forEach(timeseries_data, (series) => {
|
|
||||||
series.datapoints = dataProcessor.unShiftTimeSeries(shift, series.datapoints);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query target data for Text
|
* Query target data for Text
|
||||||
*/
|
*/
|
||||||
@@ -491,33 +443,32 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
/**
|
/**
|
||||||
* Query target data for IT Services
|
* Query target data for IT Services
|
||||||
*/
|
*/
|
||||||
queryITServiceData(target, timeRange, options) {
|
async queryITServiceData(target, timeRange, request) {
|
||||||
// Don't show undefined and hidden targets
|
// Don't show undefined and hidden targets
|
||||||
if (target.hide || (!target.itservice && !target.itServiceFilter) || !target.slaProperty) {
|
if (target.hide || (!target.itservice && !target.itServiceFilter) || !target.slaProperty) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
let itServiceFilter;
|
let itServiceFilter;
|
||||||
options.isOldVersion = target.itservice && !target.itServiceFilter;
|
request.isOldVersion = target.itservice && !target.itServiceFilter;
|
||||||
|
|
||||||
if (options.isOldVersion) {
|
if (request.isOldVersion) {
|
||||||
// Backward compatibility
|
// Backward compatibility
|
||||||
itServiceFilter = '/.*/';
|
itServiceFilter = '/.*/';
|
||||||
} else {
|
} else {
|
||||||
itServiceFilter = this.replaceTemplateVars(target.itServiceFilter, options.scopedVars);
|
itServiceFilter = this.replaceTemplateVars(target.itServiceFilter, request.scopedVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
options.slaInterval = target.slaInterval;
|
request.slaInterval = target.slaInterval;
|
||||||
|
|
||||||
return this.zabbix.getITServices(itServiceFilter)
|
let itservices = await this.zabbix.getITServices(itServiceFilter);
|
||||||
.then(itservices => {
|
if (request.isOldVersion) {
|
||||||
if (options.isOldVersion) {
|
itservices = _.filter(itservices, { 'serviceid': target.itservice?.serviceid });
|
||||||
itservices = _.filter(itservices, { 'serviceid': target.itservice?.serviceid });
|
}
|
||||||
}
|
const itservicesdp = await this.zabbix.getSLA(itservices, timeRange, target, request);
|
||||||
return this.zabbix.getSLA(itservices, timeRange, target, options);
|
const backendRequest = responseHandler.itServiceResponseToTimeSeries(itservicesdp, target.slaInterval);
|
||||||
})
|
const processedResponse = await this.invokeDataProcessingQuery(backendRequest, target);
|
||||||
.then(itservicesdp => this.applyDataProcessingFunctions(itservicesdp, target))
|
return this.handleBackendPostProcessingResponse(processedResponse, request, target);
|
||||||
.then(result => result.map(s => responseHandler.seriesToDataFrame(s, target)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queryTriggersData(target, timeRange) {
|
queryTriggersData(target, timeRange) {
|
||||||
@@ -596,7 +547,7 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (target.options?.acknowledged === 0 || target.options?.acknowledged === 1) {
|
if (target.options?.acknowledged === 0 || target.options?.acknowledged === 1) {
|
||||||
problemsOptions.acknowledged = target.options?.acknowledged ? true : false;
|
problemsOptions.acknowledged = !!target.options?.acknowledged;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.options?.minSeverity) {
|
if (target.options?.minSeverity) {
|
||||||
@@ -690,8 +641,9 @@ export class ZabbixDatasource extends DataSourceApi<ZabbixMetricsQuery, ZabbixDS
|
|||||||
* Find metrics from templated request.
|
* Find metrics from templated request.
|
||||||
*
|
*
|
||||||
* @param {string} query Query from Templating
|
* @param {string} query Query from Templating
|
||||||
|
* @param options
|
||||||
* @return {string} Metric name - group, host, app or item or list
|
* @return {string} Metric name - group, host, app or item or list
|
||||||
* of metrics in "{metric1,metcic2,...,metricN}" format.
|
* of metrics in "{metric1, metric2,..., metricN}" format.
|
||||||
*/
|
*/
|
||||||
metricFindQuery(query, options) {
|
metricFindQuery(query, options) {
|
||||||
let resultPromise;
|
let resultPromise;
|
||||||
@@ -947,12 +899,6 @@ function replaceTemplateVars(templateSrv, target, scopedVars) {
|
|||||||
return replacedTarget;
|
return replacedTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterEnabledTargets(targets) {
|
|
||||||
return _.filter(targets, target => {
|
|
||||||
return !(target.hide || !target.group || !target.host || !target.item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function base64StringToArrowTable(text: string) {
|
export function base64StringToArrowTable(text: string) {
|
||||||
const b64 = atob(text);
|
const b64 = atob(text);
|
||||||
const arr = Uint8Array.from(b64, (c) => {
|
const arr = Uint8Array.from(b64, (c) => {
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ export function seriesToDataFrame(timeseries, target: ZabbixMetricsQuery, valueM
|
|||||||
return mutableFrame;
|
return mutableFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Converts DataResponse to the format which backend works with (for data processing)
|
||||||
export function dataResponseToTimeSeries(response: DataFrameJSON[], items) {
|
export function dataResponseToTimeSeries(response: DataFrameJSON[], items) {
|
||||||
const series = [];
|
const series = [];
|
||||||
if (response.length === 0) {
|
if (response.length === 0) {
|
||||||
@@ -198,6 +199,44 @@ export function dataResponseToTimeSeries(response: DataFrameJSON[], items) {
|
|||||||
return series;
|
return series;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function itServiceResponseToTimeSeries(response: any, interval) {
|
||||||
|
const series = [];
|
||||||
|
if (response.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const s of response) {
|
||||||
|
const ts = [];
|
||||||
|
|
||||||
|
if (!s.datapoints) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dp = s.datapoints;
|
||||||
|
for (let i = 0; i < dp.length; i++) {
|
||||||
|
ts.push({ time: dp[i][1] / 1000, value: dp[i][0] });
|
||||||
|
}
|
||||||
|
|
||||||
|
let intervalS = utils.parseItemInterval(interval);
|
||||||
|
if (intervalS === 0) {
|
||||||
|
intervalS = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeSeriesData = {
|
||||||
|
ts: ts,
|
||||||
|
meta: {
|
||||||
|
name: s.target,
|
||||||
|
interval: intervalS,
|
||||||
|
item: {},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
series.push(timeSeriesData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
export function isConvertibleToWide(data: DataFrame[]): boolean {
|
export function isConvertibleToWide(data: DataFrame[]): boolean {
|
||||||
if (!data || data.length < 2) {
|
if (!data || data.length < 2) {
|
||||||
return false;
|
return false;
|
||||||
@@ -499,6 +538,7 @@ export default {
|
|||||||
sortTimeseries,
|
sortTimeseries,
|
||||||
seriesToDataFrame,
|
seriesToDataFrame,
|
||||||
dataResponseToTimeSeries,
|
dataResponseToTimeSeries,
|
||||||
|
itServiceResponseToTimeSeries,
|
||||||
isConvertibleToWide,
|
isConvertibleToWide,
|
||||||
convertToWide,
|
convertToWide,
|
||||||
alignFrames,
|
alignFrames,
|
||||||
|
|||||||
Reference in New Issue
Block a user