module.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. ## Timepicker
  3. The timepicker panel is used to select time ranges and inform other panel of
  4. them. It also handles searching for indices that match the given time range and
  5. a pattern
  6. ### Parameters
  7. * mode :: The default mode of the panel. Options: 'relative', 'absolute' 'since' Default: 'relative'
  8. * time_options :: An array of possible time options. Default: ['5m','15m','1h','6h','12h','24h','2d','7d','30d']
  9. * timespan :: The default options selected for the relative view. Default: '15m'
  10. * timefield :: The field in which time is stored in the document.
  11. * index :: Index pattern to match. Literals should be double quoted. Default: '"logstash-"yyyy.mm.dd'
  12. * refresh: Object containing refresh parameters
  13. * enable :: true/false, enable auto refresh by default. Default: false
  14. * interval :: Seconds between auto refresh. Default: 30
  15. * min :: The lowest interval a user may set
  16. ### Group Events
  17. #### Sends
  18. * time :: Object Includes from, to and index
  19. #### Receives
  20. * get_time :: Receives an object containing a uniqueid, broadcasts to it.
  21. */
  22. angular.module('kibana.timepicker', [])
  23. .controller('timepicker', function($scope, eventBus, $timeout, timer, $http) {
  24. // Set and populate defaults
  25. var _d = {
  26. mode : "relative",
  27. time_options : ['5m','15m','1h','6h','12h','24h','2d','7d','30d'],
  28. timespan : '15m',
  29. timefield : '@timestamp',
  30. index : '"logstash-"yyyy.mm.dd',
  31. defaultindex : "NOINDEX",
  32. index_interval: "day",
  33. timed_indices : true,
  34. group : "default",
  35. refresh : {
  36. enable : false,
  37. interval: 30,
  38. min : 3
  39. }
  40. }
  41. _.defaults($scope.panel,_d)
  42. var _groups = _.isArray($scope.panel.group) ?
  43. $scope.panel.group : [$scope.panel.group];
  44. $scope.init = function() {
  45. // Private refresh interval that we can use for view display without causing
  46. // unnecessary refreshes during changes
  47. $scope.refresh_interval = $scope.panel.refresh.interval
  48. // Init a private time object with Date() objects depending on mode
  49. switch($scope.panel.mode) {
  50. case 'absolute':
  51. $scope.time = {
  52. from : new Date(Date.parse($scope.panel.time.from)) || time_ago($scope.panel.timespan),
  53. to : new Date(Date.parse($scope.panel.time.to)) || new Date()
  54. }
  55. break;
  56. case 'since':
  57. $scope.time = {
  58. from : new Date(Date.parse($scope.panel.time.from)) || time_ago($scope.panel.timespan),
  59. to : new Date() || new Date()
  60. }
  61. break;
  62. case 'relative':
  63. $scope.time = {
  64. from : time_ago($scope.panel.timespan),
  65. to : new Date()
  66. }
  67. break;
  68. }
  69. $scope.time.field = $scope.panel.timefield;
  70. $scope.time_apply();
  71. // In the case that a panel is not ready to receive a time event, it may
  72. // request one be sent by broadcasting a 'get_time' with its _id to its group
  73. // This panel can handle multiple groups
  74. eventBus.register($scope,"get_time", function(event,id) {
  75. eventBus.broadcast($scope.$id,id,'time',$scope.time)
  76. });
  77. // In case some other panel broadcasts a time, set us to an absolute range
  78. eventBus.register($scope,"set_time", function(event,time) {
  79. $scope.panel.mode = 'absolute';
  80. set_timepicker(time.from,time.to)
  81. $scope.time_apply()
  82. });
  83. $scope.$on('render', function (){
  84. $scope.time_apply();
  85. });
  86. }
  87. $scope.set_interval = function (refresh_interval) {
  88. $scope.panel.refresh.interval = refresh_interval
  89. if(_.isNumber($scope.panel.refresh.interval)) {
  90. if($scope.panel.refresh.interval < $scope.panel.refresh.min) {
  91. $scope.panel.refresh.interval = $scope.panel.refresh.min
  92. timer.cancel($scope.refresh_timer)
  93. return;
  94. }
  95. timer.cancel($scope.refresh_timer)
  96. $scope.refresh()
  97. } else {
  98. timer.cancel($scope.refresh_timer)
  99. }
  100. }
  101. $scope.refresh = function() {
  102. if ($scope.panel.refresh.enable) {
  103. timer.cancel($scope.refresh_timer)
  104. $scope.refresh_timer = timer.register($timeout(function() {
  105. $scope.refresh();
  106. $scope.time_apply();
  107. },$scope.panel.refresh.interval*1000
  108. ));
  109. } else {
  110. timer.cancel($scope.refresh_timer)
  111. }
  112. }
  113. $scope.set_mode = function(mode) {
  114. $scope.panel.mode = mode;
  115. $scope.panel.refresh.enable = mode === 'absolute' ?
  116. false : $scope.panel.refresh.enable
  117. }
  118. $scope.to_now = function() {
  119. $scope.timepicker.to = {
  120. time : new Date().format("HH:MM:ss"),
  121. date : new Date().format("mm/dd/yyyy")
  122. }
  123. }
  124. $scope.set_timespan = function(timespan) {
  125. $scope.panel.timespan = timespan;
  126. $scope.timepicker.from = {
  127. time : time_ago(timespan).format("HH:MM:ss"),
  128. date : time_ago(timespan).format("mm/dd/yyyy")
  129. }
  130. $scope.time_apply();
  131. }
  132. $scope.time_check = function(){
  133. // If time picker is defined (on initialization)
  134. if(!(_.isUndefined($scope.timepicker))) {
  135. var from = $scope.panel.mode === 'relative' ? time_ago($scope.panel.timespan) :
  136. new Date(Date.parse($scope.timepicker.from.date + " " + $scope.timepicker.from.time))
  137. var to = $scope.panel.mode !== 'absolute' ? new Date() :
  138. new Date(Date.parse($scope.timepicker.to.date + " " + $scope.timepicker.to.time))
  139. // Otherwise
  140. } else {
  141. var from = $scope.panel.mode === 'relative' ? time_ago($scope.panel.timespan) :
  142. $scope.time.from;
  143. var to = $scope.panel.mode !== 'absolute' ? new Date() :
  144. $scope.time.to;
  145. }
  146. if (from.getTime() >= to.getTime())
  147. from = new Date(to.getTime() - 1000)
  148. $timeout(function(){
  149. set_timepicker(from,to)
  150. });
  151. return {
  152. from : from,
  153. to : to
  154. };
  155. }
  156. $scope.time_apply = function() {
  157. // Update internal time object
  158. $scope.time = $scope.time_check();
  159. $scope.time.field = $scope.panel.timefield
  160. // Get indices for the time period, then broadcast time range and index list
  161. // in a single object. Not sure if I like this.
  162. if($scope.panel.timed_indices) {
  163. indices($scope.time.from,$scope.time.to).then(function (p) {
  164. $scope.time.index = p;
  165. eventBus.broadcast($scope.$id,$scope.panel.group,'time',$scope.time)
  166. });
  167. } else {
  168. $scope.time.index = [$scope.panel.index];
  169. eventBus.broadcast($scope.$id,$scope.panel.group,'time',$scope.time)
  170. }
  171. // Update panel's string representation of the time object
  172. $scope.panel.time = {
  173. from : $scope.time.from.format("mm/dd/yyyy HH:MM:ss"),
  174. to : $scope.time.to.format("mm/dd/yyyy HH:MM:ss"),
  175. index : $scope.time.index,
  176. };
  177. };
  178. function set_timepicker(from,to) {
  179. // Janky 0s timeout to get around $scope queue processing view issue
  180. $scope.timepicker = {
  181. from : {
  182. time : from.format("HH:MM:ss"),
  183. date : from.format("mm/dd/yyyy")
  184. },
  185. to : {
  186. time : to.format("HH:MM:ss"),
  187. date : to.format("mm/dd/yyyy")
  188. }
  189. }
  190. }
  191. // returns a promise containing an array of all indices matching the index
  192. // pattern that exist in a given range
  193. function indices(from,to) {
  194. var possible = [];
  195. _.each(expand_range(fake_utc(from),fake_utc(to),$scope.panel.index_interval),function(d){
  196. possible.push(d.format($scope.panel.index));
  197. });
  198. return all_indices().then(function(p) {
  199. var indices = _.intersection(possible,p);
  200. indices.reverse();
  201. return indices.length == 0 ? [$scope.panel.defaultindex] : indices;
  202. })
  203. };
  204. // returns a promise containing an array of all indices in an elasticsearch
  205. // cluster
  206. function all_indices() {
  207. var something = $http({
  208. url: config.elasticsearch + "/_aliases",
  209. method: "GET"
  210. }).error(function(data, status, headers, config) {
  211. $scope.error = status;
  212. });
  213. return something.then(function(p) {
  214. var indices = [];
  215. _.each(p.data, function(v,k) {
  216. indices.push(k)
  217. });
  218. return indices;
  219. });
  220. }
  221. // this is stupid, but there is otherwise no good way to ensure that when
  222. // I extract the date from an object that I'm get the UTC date. Stupid js.
  223. // I die a little inside every time I call this function.
  224. function fake_utc(date) {
  225. return new Date(date.getTime() + date.getTimezoneOffset() * 60000);
  226. }
  227. // Create an array of date objects by a given interval
  228. function expand_range(start, end, interval) {
  229. if(_.contains(['hour','day','week','month','year'],interval)) {
  230. var range;
  231. start = start.clone();
  232. range = [];
  233. while (start.isBefore(end)) {
  234. range.push(start.clone());
  235. switch (interval) {
  236. case 'hour':
  237. start.addHours(1)
  238. break
  239. case 'day':
  240. start.addDays(1)
  241. break
  242. case 'week':
  243. start.addWeeks(1)
  244. break
  245. case 'month':
  246. start.addMonths(1)
  247. break
  248. case 'year':
  249. start.addYears(1)
  250. break
  251. }
  252. }
  253. range.push(end.clone());
  254. return range;
  255. } else {
  256. return false;
  257. }
  258. }
  259. })