Merge branch 'master' into tests

This commit is contained in:
Alexander Zobnin
2016-11-09 14:44:43 +03:00
20 changed files with 437 additions and 78 deletions

View File

@@ -116,6 +116,22 @@ export default class DataProcessor {
return sortByTime(new_timeseries);
}
static limit(order, n, orderByFunc, timeseries) {
let orderByCallback = DataProcessor.aggregationFunctions[orderByFunc];
let sortByIteratee = (ts) => {
let values = _.map(ts.datapoints, (point) => {
return point[0];
});
return orderByCallback(values);
};
let sortedTimeseries = _.sortBy(timeseries, sortByIteratee);
if (order === 'bottom') {
return sortedTimeseries.slice(0, n);
} else {
return sortedTimeseries.slice(-n);
}
}
static AVERAGE(values) {
var sum = 0;
_.each(values, function(value) {
@@ -151,6 +167,16 @@ export default class DataProcessor {
});
}
static delta(datapoints) {
let newSeries = [];
let deltaValue;
for (var i = 1; i < datapoints.length; i++) {
deltaValue = datapoints[i][0] - datapoints[i - 1][0];
newSeries.push([deltaValue, datapoints[i][1]]);
}
return newSeries;
}
static groupByWrapper(interval, groupFunc, datapoints) {
var groupByCallback = DataProcessor.aggregationFunctions[groupFunc];
return DataProcessor.groupBy(interval, groupByCallback, datapoints);
@@ -181,12 +207,15 @@ export default class DataProcessor {
return {
groupBy: this.groupByWrapper,
scale: this.scale,
delta: this.delta,
aggregateBy: this.aggregateByWrapper,
average: _.partial(this.aggregateWrapper, this.AVERAGE),
min: _.partial(this.aggregateWrapper, this.MIN),
max: _.partial(this.aggregateWrapper, this.MAX),
median: _.partial(this.aggregateWrapper, this.MEDIAN),
sumSeries: this.sumSeries,
top: _.partial(this.limit, 'top'),
bottom: _.partial(this.limit, 'bottom'),
setAlias: this.setAlias,
};
}

View File

@@ -92,7 +92,11 @@ export class ZabbixAPIDatasource {
_.forEach(target.functions, func => {
func.params = _.map(func.params, param => {
return this.templateSrv.replace(param, options.scopedVars);
if (typeof param === 'number') {
return +this.templateSrv.replace(param.toString(), options.scopedVars);
} else {
return this.templateSrv.replace(param, options.scopedVars);
}
});
});
@@ -158,7 +162,7 @@ export class ZabbixAPIDatasource {
// Find trendValue() function and get specified trend value
var trendFunctions = _.map(metricFunctions.getCategories()['Trends'], 'name');
var trendValueFunc = _.find(target.functions, func => {
return _.contains(trendFunctions, func.def.name);
return _.includes(trendFunctions, func.def.name);
});
var valueType = trendValueFunc ? trendValueFunc.params[0] : "avg";
@@ -181,6 +185,7 @@ export class ZabbixAPIDatasource {
return getHistory.then(timeseries_data => {
let transformFunctions = bindFunctionDefs(target.functions, 'Transform');
let aggregationFunctions = bindFunctionDefs(target.functions, 'Aggregate');
let filterFunctions = bindFunctionDefs(target.functions, 'Filter');
let aliasFunctions = bindFunctionDefs(target.functions, 'Alias');
// Apply transformation functions
@@ -189,6 +194,11 @@ export class ZabbixAPIDatasource {
return timeseries;
});
// Apply filter functions
if (filterFunctions.length) {
timeseries_data = sequence(filterFunctions)(timeseries_data);
}
// Apply aggregations
if (aggregationFunctions.length) {
let dp = _.map(timeseries_data, 'datapoints');
@@ -196,7 +206,7 @@ export class ZabbixAPIDatasource {
let aggFuncNames = _.map(metricFunctions.getCategories()['Aggregate'], 'name');
let lastAgg = _.findLast(target.functions, func => {
return _.contains(aggFuncNames, func.def.name);
return _.includes(aggFuncNames, func.def.name);
});
timeseries_data = [
@@ -247,10 +257,9 @@ export class ZabbixAPIDatasource {
* @return {object} Connection status and Zabbix API version
*/
testDatasource() {
var self = this;
return this.zabbixAPI.getVersion()
.then(version => {
return self.zabbixAPI.login()
return this.zabbixAPI.login()
.then(auth => {
if (auth) {
return {
@@ -307,7 +316,7 @@ export class ZabbixAPIDatasource {
}
parts.push(part);
});
let template = _.object(['group', 'host', 'app', 'item'], parts);
let template = _.zipObject(['group', 'host', 'app', 'item'], parts);
// Get items
if (parts.length === 4) {
@@ -351,11 +360,10 @@ export class ZabbixAPIDatasource {
.buildTriggerQuery(this.replaceTemplateVars(annotation.group, {}),
this.replaceTemplateVars(annotation.host, {}),
this.replaceTemplateVars(annotation.application, {}));
var self = this;
return buildQuery.then(query => {
return self.zabbixAPI
.getTriggers(query.groupids, query.hostids, query.applicationids,
showTriggers, timeFrom, timeTo)
return this.zabbixAPI
.getTriggers(query.groupids, query.hostids, query.applicationids, showTriggers)
.then(triggers => {
// Filter triggers by description
@@ -375,10 +383,10 @@ export class ZabbixAPIDatasource {
});
var objectids = _.map(triggers, 'triggerid');
return self.zabbixAPI
return this.zabbixAPI
.getEvents(objectids, timeFrom, timeTo, showOkEvents)
.then(events => {
var indexedTriggers = _.indexBy(triggers, 'triggerid');
var indexedTriggers = _.keyBy(triggers, 'triggerid');
// Hide acknowledged events if option enabled
if (annotation.hideAcknowledged) {
@@ -388,19 +396,20 @@ export class ZabbixAPIDatasource {
}
return _.map(events, event => {
var title ='';
let tags;
if (annotation.showHostname) {
title += event.hosts[0].name + ': ';
tags = _.map(event.hosts, 'name');
}
// Show event type (OK or Problem)
title += Number(event.value) ? 'Problem' : 'OK';
let title = Number(event.value) ? 'Problem' : 'OK';
var formatted_acknowledges = utils.formatAcknowledges(event.acknowledges);
let formatted_acknowledges = utils.formatAcknowledges(event.acknowledges);
return {
annotation: annotation,
time: event.clock * 1000,
title: title,
tags: tags,
text: indexedTriggers[event.objectid].description + formatted_acknowledges
};
});
@@ -414,7 +423,7 @@ export class ZabbixAPIDatasource {
function bindFunctionDefs(functionDefs, category) {
var aggregationFunctions = _.map(metricFunctions.getCategories()[category], 'name');
var aggFuncDefs = _.filter(functionDefs, function(func) {
return _.contains(aggregationFunctions, func.def.name);
return _.includes(aggregationFunctions, func.def.name);
});
return _.map(aggFuncDefs, function(func) {
@@ -423,13 +432,6 @@ function bindFunctionDefs(functionDefs, category) {
});
}
function filterFunctionDefs(funcs, category) {
let filteredFuncs = _.map(metricFunctions.getCategories()[category]);
return _.filter(funcs, func => {
return _.contains(filteredFuncs, func.def.name);
});
}
function formatMetric(metricObj) {
return {
text: metricObj.name,
@@ -447,7 +449,7 @@ function formatMetric(metricObj) {
* template variables, for example
* /CPU $cpu_item.*time/ where $cpu_item is system,user,iowait
*/
function zabbixTemplateFormat(value, variable) {
function zabbixTemplateFormat(value) {
if (typeof value === 'string') {
return utils.escapeRegex(value);
}
@@ -456,7 +458,8 @@ function zabbixTemplateFormat(value, variable) {
return '(' + escapedValues.join('|') + ')';
}
/** If template variables are used in request, replace it using regex format
/**
* If template variables are used in request, replace it using regex format
* and wrap with '/' for proper multi-value work. Example:
* $variable selected as a, b, c
* We use filter $variable
@@ -494,3 +497,7 @@ function sequence(funcsArray) {
return result;
};
}
// Fix for backward compatibility with lodash 2.4
if (!_.includes) {_.includes = _.contains;}
if (!_.keyBy) {_.keyBy = _.indexBy;}

View File

@@ -5,6 +5,7 @@ var index = [];
var categories = {
Transform: [],
Aggregate: [],
Filter: [],
Trends: [],
Alias: []
};
@@ -39,6 +40,13 @@ addFuncDef({
defaultParams: [100],
});
addFuncDef({
name: 'delta',
category: 'Transform',
params: [],
defaultParams: [],
});
addFuncDef({
name: 'sumSeries',
category: 'Aggregate',
@@ -92,6 +100,26 @@ addFuncDef({
defaultParams: ['1m', 'avg'],
});
addFuncDef({
name: 'top',
category: 'Filter',
params: [
{ name: 'number', type: 'int' },
{ name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }
],
defaultParams: [5, 'avg'],
});
addFuncDef({
name: 'bottom',
category: 'Filter',
params: [
{ name: 'number', type: 'int' },
{ name: 'value', type: 'string', options: ['avg', 'min', 'max', 'median'] }
],
defaultParams: [5, 'avg'],
});
addFuncDef({
name: 'trendValue',
category: 'Trends',

View File

@@ -1,4 +1,5 @@
import {QueryCtrl} from 'app/plugins/sdk';
import angular from 'angular';
import _ from 'lodash';
import * as utils from './utils';
import * as metricFunctions from './metricFunctions';

View File

@@ -230,13 +230,13 @@ angular.module('grafana.services').factory('QueryProcessor', function($q) {
// Group history by itemid
var grouped_history = _.groupBy(history, 'itemid');
var hosts = _.indexBy(_.flatten(_.map(items, 'hosts')), 'hostid');
var hosts = _.uniq(_.flatten(_.map(items, 'hosts')),'hostid'); //uniq is needed to deduplicate
return _.map(grouped_history, function(hist, itemid) {
var item = _.find(items, {'itemid': itemid});
var alias = item.name;
if (_.keys(hosts).length > 1 || addHostName) {
var host = hosts[item.hostid];
if (_.keys(hosts).length > 1 && addHostName) { //only when actual multi hosts selected
var host = _.find(hosts, {'hostid': item.hostid});
alias = host.name + ": " + alias;
}
return {
@@ -335,12 +335,6 @@ function getByFilter(list, filter) {
}
}
function getFromIndex(index, objids) {
return _.map(objids, function(id) {
return index[id];
});
}
function convertHistoryPoint(point) {
// Value must be a number for properly work
return [

View File

@@ -1,7 +1,6 @@
import _ from 'lodash';
import moment from 'moment';
/**
* Expand Zabbix item name
*
@@ -35,7 +34,7 @@ export function isTemplateVariable(str, templateVariables) {
var variables = _.map(templateVariables, variable => {
return '$' + variable.name;
});
return _.contains(variables, str);
return _.includes(variables, str);
} else {
return false;
}
@@ -93,3 +92,8 @@ export function convertToZabbixAPIUrl(url) {
return url.replace(trimSlashPattern, "$1");
}
}
// Fix for backward compatibility with lodash 2.4
if (!_.includes) {
_.includes = _.contains;
}

View File

@@ -41,12 +41,12 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) {
request(method, params) {
var self = this;
return this.zabbixAPICore.request(this.url, method, params, this.requestOptions, this.auth)
.then(function(result) {
return this.zabbixAPICore
.request(this.url, method, params, this.requestOptions, this.auth)
.then((result) => {
return result;
},
// Handle API errors
function(error) {
}, (error) => {
// Handle API errors
if (isNotAuthorized(error.data)) {
return self.loginOnce().then(
function() {
@@ -56,15 +56,18 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) {
function(error) {
self.alertAPIError(error.data);
});
} else {
this.alertSrv.set("Connection Error", error.data, 'error', 5000);
}
});
}
alertAPIError(message) {
alertAPIError(message, timeout = 5000) {
this.alertSrv.set(
"Zabbix API Error",
message,
'error'
'error',
timeout
);
}
@@ -336,6 +339,7 @@ function ZabbixAPIService($q, alertSrv, zabbixAPICoreService) {
applicationids: applicationids,
expandDescription: true,
expandData: true,
expandComment: true,
monitored: true,
skipDependent: true,
//only_true: true,

View File

@@ -51,19 +51,23 @@ class ZabbixAPICoreService {
requestOptions.headers.Authorization = options.basicAuth;
}
this.backendSrv.datasourceRequest(requestOptions).then(function (response) {
// General connection issues
if (!response.data) {
deferred.reject(response);
}
this.backendSrv.datasourceRequest(requestOptions)
.then((response) => {
// General connection issues
if (!response.data) {
deferred.reject(response);
}
// Handle Zabbix API errors
else if (response.data.error) {
deferred.reject(response.data.error);
}
// Handle Zabbix API errors
else if (response.data.error) {
deferred.reject(response.data.error);
}
deferred.resolve(response.data.result);
}, (error) => {
deferred.reject(error.err);
});
deferred.resolve(response.data.result);
});
return deferred.promise;
}

View File

@@ -1,6 +1,5 @@
import angular from 'angular';
import _ from 'lodash';
import * as utils from './utils';
// Use factory() instead service() for multiple datasources support.
// Each datasource instance must initialize its own cache.
@@ -117,7 +116,7 @@ angular.module('grafana.services').factory('ZabbixCachingProxy', function($q, $i
var deferred = this.$q.defer();
var historyStorage = this.storage.history;
var full_history;
var expired = _.filter(_.indexBy(items, 'itemid'), function(item, itemid) {
var expired = _.filter(_.keyBy(items, 'itemid'), function(item, itemid) {
return !historyStorage[itemid];
});
if (expired.length) {
@@ -236,3 +235,6 @@ String.prototype.getHash = function() {
}
return hash;
};
// Fix for backward compatibility with lodash 2.4
if (!_.keyBy) {_.keyBy = _.indexBy;}