Commit 8a9661bf by Spencer Alger

Added a time series service, which provides a ZeroFilled class, setup the…

Added a time series service, which provides a ZeroFilled class, setup the histogram to use it so that zero measurements will be displayed
parent 3b9bc6bc
...@@ -30,7 +30,7 @@ angular.module('kibana.services', []) ...@@ -30,7 +30,7 @@ angular.module('kibana.services', [])
this.clearAll = function() { this.clearAll = function() {
self.list = []; self.list = [];
}; };
}) })
.service('fields', function(dashboard, $rootScope, $http, alertSrv) { .service('fields', function(dashboard, $rootScope, $http, alertSrv) {
...@@ -116,7 +116,7 @@ angular.module('kibana.services', []) ...@@ -116,7 +116,7 @@ angular.module('kibana.services', [])
ret[propName] = obj; ret[propName] = obj;
} }
} }
return ret; return ret;
}; };
}) })
...@@ -242,11 +242,11 @@ angular.module('kibana.services', []) ...@@ -242,11 +242,11 @@ angular.module('kibana.services', [])
ids : [], ids : [],
}); });
// For convenience // For convenience
var ejs = ejsResource(config.elasticsearch); var ejs = ejsResource(config.elasticsearch);
var _q = dashboard.current.services.query; var _q = dashboard.current.services.query;
this.colors = [ this.colors = [
"#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", //1 "#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", //1
"#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", //2 "#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", //2
"#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", //3 "#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", //3
...@@ -264,7 +264,7 @@ angular.module('kibana.services', []) ...@@ -264,7 +264,7 @@ angular.module('kibana.services', [])
_q = dashboard.current.services.query; _q = dashboard.current.services.query;
self.list = dashboard.current.services.query.list; self.list = dashboard.current.services.query.list;
self.ids = dashboard.current.services.query.ids; self.ids = dashboard.current.services.query.ids;
if (self.ids.length === 0) { if (self.ids.length === 0) {
self.set({}); self.set({});
} }
...@@ -330,7 +330,7 @@ angular.module('kibana.services', []) ...@@ -330,7 +330,7 @@ angular.module('kibana.services', [])
}; };
this.idsByMode = function(config) { this.idsByMode = function(config) {
switch(config.mode) switch(config.mode)
{ {
case 'all': case 'all':
return self.ids; return self.ids;
...@@ -370,7 +370,7 @@ angular.module('kibana.services', []) ...@@ -370,7 +370,7 @@ angular.module('kibana.services', [])
}); });
// For convenience // For convenience
var ejs = ejsResource(config.elasticsearch); var ejs = ejsResource(config.elasticsearch);
var _f = dashboard.current.services.filter; var _f = dashboard.current.services.filter;
// Save a reference to this // Save a reference to this
...@@ -390,7 +390,7 @@ angular.module('kibana.services', []) ...@@ -390,7 +390,7 @@ angular.module('kibana.services', [])
}; };
// This is used both for adding filters and modifying them. // This is used both for adding filters and modifying them.
// If an id is passed, the filter at that id is updated // If an id is passed, the filter at that id is updated
this.set = function(filter,id) { this.set = function(filter,id) {
_.defaults(filter,{mandate:'must'}); _.defaults(filter,{mandate:'must'});
...@@ -425,7 +425,7 @@ angular.module('kibana.services', []) ...@@ -425,7 +425,7 @@ angular.module('kibana.services', [])
var either_bool = ejs.BoolFilter().must(ejs.MatchAllFilter()); var either_bool = ejs.BoolFilter().must(ejs.MatchAllFilter());
_.each(ids,function(id) { _.each(ids,function(id) {
if(self.list[id].active) { if(self.list[id].active) {
switch(self.list[id].mandate) switch(self.list[id].mandate)
{ {
case 'mustNot': case 'mustNot':
bool = bool.mustNot(self.getEjsObj(id)); bool = bool.mustNot(self.getEjsObj(id));
...@@ -563,7 +563,7 @@ angular.module('kibana.services', []) ...@@ -563,7 +563,7 @@ angular.module('kibana.services', [])
}; };
// An elasticJS client to use // An elasticJS client to use
var ejs = ejsResource(config.elasticsearch); var ejs = ejsResource(config.elasticsearch);
var gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/; var gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
// Store a reference to this // Store a reference to this
...@@ -602,8 +602,8 @@ angular.module('kibana.services', []) ...@@ -602,8 +602,8 @@ angular.module('kibana.services', [])
// No dashboard in the URL // No dashboard in the URL
} else { } else {
// Check if browser supports localstorage, and if there's a dashboard // Check if browser supports localstorage, and if there's a dashboard
if (window.Modernizr.localstorage && if (window.Modernizr.localstorage &&
!(_.isUndefined(window.localStorage['dashboard'])) && !(_.isUndefined(window.localStorage['dashboard'])) &&
window.localStorage['dashboard'] !== '' window.localStorage['dashboard'] !== ''
) { ) {
...@@ -612,11 +612,11 @@ angular.module('kibana.services', []) ...@@ -612,11 +612,11 @@ angular.module('kibana.services', [])
// No? Ok, grab default.json, its all we have now // No? Ok, grab default.json, its all we have now
} else { } else {
self.file_load('default.json'); self.file_load('default.json');
} }
} }
}; };
// Since the dashboard is responsible for index computation, we can compute and assign the indices // Since the dashboard is responsible for index computation, we can compute and assign the indices
// here before telling the panels to refresh // here before telling the panels to refresh
this.refresh = function() { this.refresh = function() {
if(self.current.index.interval !== 'none') { if(self.current.index.interval !== 'none') {
...@@ -626,7 +626,7 @@ angular.module('kibana.services', []) ...@@ -626,7 +626,7 @@ angular.module('kibana.services', [])
self.current.index.pattern,self.current.index.interval self.current.index.pattern,self.current.index.interval
).then(function (p) { ).then(function (p) {
if(p.length > 0) { if(p.length > 0) {
self.indices = p; self.indices = p;
} else { } else {
//TODO: Option to not failover //TODO: Option to not failover
if(self.current.failover) { if(self.current.failover) {
...@@ -711,7 +711,7 @@ angular.module('kibana.services', []) ...@@ -711,7 +711,7 @@ angular.module('kibana.services', [])
return true; return true;
} else { } else {
return false; return false;
} }
}; };
this.purge_default = function() { this.purge_default = function() {
...@@ -770,7 +770,7 @@ angular.module('kibana.services', []) ...@@ -770,7 +770,7 @@ angular.module('kibana.services', [])
// Clone object so we can modify it without influencing the existing obejct // Clone object so we can modify it without influencing the existing obejct
var save = _.clone(self.current); var save = _.clone(self.current);
var id; var id;
// Change title on object clone // Change title on object clone
if (type === 'dashboard') { if (type === 'dashboard') {
id = save.title = _.isUndefined(title) ? self.current.title : title; id = save.title = _.isUndefined(title) ? self.current.title : title;
...@@ -783,7 +783,7 @@ angular.module('kibana.services', []) ...@@ -783,7 +783,7 @@ angular.module('kibana.services', [])
title: save.title, title: save.title,
dashboard: angular.toJson(save) dashboard: angular.toJson(save)
}); });
request = type === 'temp' && ttl ? request.ttl(ttl) : request; request = type === 'temp' && ttl ? request.ttl(ttl) : request;
// TOFIX: Implement error handling here // TOFIX: Implement error handling here
...@@ -868,5 +868,79 @@ angular.module('kibana.services', []) ...@@ -868,5 +868,79 @@ angular.module('kibana.services', [])
return false; return false;
}); });
}; };
})
.service('timeSeries', function () {
/**
* Certain graphs require 0 entries to be specified for them to render
* properly (like the line graph). So with this we will caluclate all of
* the expected time measurements, and fill the missing ones in with 0
* @param date start The start time for the result set
* @param date end The end time for the result set
* @param integer interval The length between measurements, in es interval
* notation (1m, 30s, 1h, 15d)
*/
var undef;
function dateToSecondsWithBlankMs(date) {
// return the date as millis since epoch, with 0 millis
return Math.floor(date.getTime() / 1000)*1000;
}
function base10Int(val) {
return parseInt(val, 10);
}
this.ZeroFilled = function (interval, start, end) {
// the expected differenece between readings.
this.interval_ms = parseInt(kbn.interval_to_seconds(interval), 10) * 1000;
// will keep all values here, keyed by their time
this._data = {};
if (start) {
this.addValue(start, null);
}
if (end) {
this.addValue(end, null);
}
}
/**
* Add a row
* @param int time The time for the value, in
* @param any value The value at this time
*/
this.ZeroFilled.prototype.addValue = function (time, value) {
if (time instanceof Date) {
time = dateToSecondsWithBlankMs(time);
} else {
time = parseInt(time, 10);
}
if (!isNaN(time)) {
this._data[time] = (value === undef ? 0 : value);
}
};
/**
* return the rows in the format:
* [ [time, value], [time, value], ... ]
* @return array
*/
this.ZeroFilled.prototype.getFlotPairs = function () {
// var startTime = performance.now();
var times = _.map(_.keys(this._data), base10Int).sort()
, result = []
, i
, next
, expected_next;
for(i = 0; i < times.length; i++) {
result.push([ times[i], this._data[times[i]] ]);
next = times[i + 1];
expected_next = times[i] + this.interval_ms;
for(; times.length > i && next > expected_next; expected_next+= this.interval_ms) {
/**
* since we don't know how the server will round subsequent segments
* we have to recheck for blanks each time.
*/
// this._data[expected_next] = 0;
result.push([expected_next, 0]);
}
}
// console.log(Math.round((performance.now() - startTime)*100)/100, 'ms to get', result.length, 'pairs');
return result;
};
}); });
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment