module.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /** @scratch /panels/5
  2. * include::panels/histogram.asciidoc[]
  3. */
  4. /** @scratch /panels/histogram/0
  5. * == Histogram
  6. * Status: *Stable*
  7. *
  8. * The histogram panel allow for the display of time charts. It includes several modes and tranformations
  9. * to display event counts, mean, min, max and total of numeric fields, and derivatives of counter
  10. * fields.
  11. *
  12. */
  13. define([
  14. 'angular',
  15. 'app',
  16. 'jquery',
  17. 'underscore',
  18. 'kbn',
  19. 'moment',
  20. './timeSeries',
  21. 'jquery.flot',
  22. 'jquery.flot.events',
  23. 'jquery.flot.selection',
  24. 'jquery.flot.time',
  25. 'jquery.flot.byte',
  26. 'jquery.flot.stack',
  27. 'jquery.flot.stackpercent'
  28. ],
  29. function (angular, app, $, _, kbn, moment, timeSeries) {
  30. 'use strict';
  31. var module = angular.module('kibana.panels.graphite', []);
  32. app.useModule(module);
  33. module.controller('graphite', function($scope, $rootScope, filterSrv, datasourceSrv, $timeout, annotationsSrv) {
  34. $scope.panelMeta = {
  35. modals : [],
  36. editorTabs: [],
  37. fullEditorTabs : [
  38. {
  39. title: 'General',
  40. src:'app/partials/panelgeneral.html'
  41. },
  42. {
  43. title: 'Metrics',
  44. src:'app/partials/metrics.html'
  45. },
  46. {
  47. title:'Axes & Grid',
  48. src:'app/panels/graphite/axisEditor.html'
  49. },
  50. {
  51. title:'Display Styles',
  52. src:'app/panels/graphite/styleEditor.html'
  53. }
  54. ],
  55. fullscreenEdit: true,
  56. fullscreenView: true,
  57. description : "Graphing"
  58. };
  59. // Set and populate defaults
  60. var _d = {
  61. datasource: null,
  62. /** @scratch /panels/histogram/3
  63. * renderer:: sets client side (flot) or native graphite png renderer (png)
  64. */
  65. renderer: 'flot',
  66. /** @scratch /panels/histogram/3
  67. * x-axis:: Show the x-axis
  68. */
  69. 'x-axis' : true,
  70. /** @scratch /panels/histogram/3
  71. * y-axis:: Show the y-axis
  72. */
  73. 'y-axis' : true,
  74. /** @scratch /panels/histogram/3
  75. * scale:: Scale the y-axis by this factor
  76. */
  77. scale : 1,
  78. /** @scratch /panels/histogram/3
  79. * y_formats :: 'none','bytes','bits','short', 'ms'
  80. */
  81. y_formats : ['short', 'short'],
  82. /** @scratch /panels/histogram/5
  83. * grid object:: Min and max y-axis values
  84. * grid.min::: Minimum y-axis value
  85. * grid.ma1::: Maximum y-axis value
  86. */
  87. grid : {
  88. max: null,
  89. min: 0,
  90. threshold1: null,
  91. threshold2: null,
  92. threshold1Color: 'rgba(216, 200, 27, 0.27)',
  93. threshold2Color: 'rgba(234, 112, 112, 0.22)'
  94. },
  95. annotate : {
  96. enable : false,
  97. },
  98. /** @scratch /panels/histogram/3
  99. * resolution:: If auto_int is true, shoot for this many bars.
  100. */
  101. resolution : 100,
  102. /** @scratch /panels/histogram/3
  103. * ==== Drawing options
  104. * lines:: Show line chart
  105. */
  106. lines : true,
  107. /** @scratch /panels/histogram/3
  108. * fill:: Area fill factor for line charts, 1-10
  109. */
  110. fill : 0,
  111. /** @scratch /panels/histogram/3
  112. * linewidth:: Weight of lines in pixels
  113. */
  114. linewidth : 1,
  115. /** @scratch /panels/histogram/3
  116. * points:: Show points on chart
  117. */
  118. points : false,
  119. /** @scratch /panels/histogram/3
  120. * pointradius:: Size of points in pixels
  121. */
  122. pointradius : 5,
  123. /** @scratch /panels/histogram/3
  124. * bars:: Show bars on chart
  125. */
  126. bars : false,
  127. /** @scratch /panels/histogram/3
  128. * stack:: Stack multiple series
  129. */
  130. stack : false,
  131. /** @scratch /panels/histogram/3
  132. * legend:: Display the legond
  133. */
  134. legend: {
  135. show: true, // disable/enable legend
  136. values: false, // disable/enable legend values
  137. min: false,
  138. max: false,
  139. current: false,
  140. total: false,
  141. avg: false
  142. },
  143. /** @scratch /panels/histogram/3
  144. * ==== Transformations
  145. /** @scratch /panels/histogram/3
  146. * percentage:: Show the y-axis as a percentage of the axis total. Only makes sense for multiple
  147. * queries
  148. */
  149. percentage : false,
  150. /** @scratch /panels/histogram/3
  151. * zerofill:: Improves the accuracy of line charts at a small performance cost.
  152. */
  153. zerofill : true,
  154. nullPointMode : 'connected',
  155. steppedLine: false,
  156. tooltip : {
  157. value_type: 'cumulative',
  158. query_as_alias: true
  159. },
  160. targets: [],
  161. aliasColors: {},
  162. aliasYAxis: {},
  163. };
  164. _.defaults($scope.panel,_d);
  165. _.defaults($scope.panel.tooltip, _d.tooltip);
  166. _.defaults($scope.panel.annotate, _d.annotate);
  167. _.defaults($scope.panel.grid, _d.grid);
  168. // backward compatible stuff
  169. if (_.isBoolean($scope.panel.legend)) {
  170. $scope.panel.legend = { show: $scope.panel.legend };
  171. _.defaults($scope.panel.legend, _d.legend);
  172. }
  173. if ($scope.panel.y_format) {
  174. $scope.panel.y_formats[0] = $scope.panel.y_format;
  175. delete $scope.panel.y_format;
  176. }
  177. if ($scope.panel.y2_format) {
  178. $scope.panel.y_formats[1] = $scope.panel.y2_format;
  179. delete $scope.panel.y2_format;
  180. }
  181. $scope.init = function() {
  182. $scope.initPanel($scope);
  183. $scope.fullscreen = false;
  184. $scope.editor = { index: 1 };
  185. $scope.editorTabs = _.pluck($scope.panelMeta.fullEditorTabs,'title');
  186. $scope.hiddenSeries = {};
  187. $scope.datasources = datasourceSrv.listOptions();
  188. $scope.setDatasource($scope.panel.datasource);
  189. };
  190. $scope.setDatasource = function(datasource) {
  191. $scope.panel.datasource = datasource;
  192. $scope.datasource = datasourceSrv.get(datasource);
  193. if (!$scope.datasource) {
  194. $scope.panel.error = "Cannot find datasource " + datasource;
  195. return;
  196. }
  197. $scope.get_data();
  198. };
  199. $scope.removeTarget = function (target) {
  200. $scope.panel.targets = _.without($scope.panel.targets, target);
  201. $scope.get_data();
  202. };
  203. $scope.updateTimeRange = function () {
  204. $scope.range = filterSrv.timeRange();
  205. $scope.rangeUnparsed = filterSrv.timeRange(false);
  206. $scope.resolution = Math.ceil(($(window).width() * ($scope.panel.span / 12)) / 2);
  207. $scope.interval = '10m';
  208. if ($scope.range) {
  209. $scope.interval = kbn.secondsToHms(
  210. kbn.calculate_interval($scope.range.from, $scope.range.to, $scope.resolution, 0) / 1000
  211. );
  212. }
  213. };
  214. $scope.get_data = function() {
  215. delete $scope.panel.error;
  216. $scope.panelMeta.loading = true;
  217. $scope.updateTimeRange();
  218. var graphiteQuery = {
  219. range: $scope.rangeUnparsed,
  220. interval: $scope.interval,
  221. targets: $scope.panel.targets,
  222. format: $scope.panel.renderer === 'png' ? 'png' : 'json',
  223. maxDataPoints: $scope.resolution,
  224. datasource: $scope.panel.datasource
  225. };
  226. $scope.annotationsPromise = annotationsSrv.getAnnotations($scope.rangeUnparsed);
  227. return $scope.datasource.query(graphiteQuery)
  228. .then($scope.dataHandler)
  229. .then(null, function(err) {
  230. $scope.panelMeta.loading = false;
  231. $scope.inspector_info = { error: err };
  232. $scope.panel.error = err.message || "Graphite HTTP Request Error";
  233. $scope.render([]);
  234. });
  235. };
  236. $scope.dataHandler = function(results) {
  237. $scope.panelMeta.loading = false;
  238. $scope.legend = [];
  239. // png renderer returns just a url
  240. if (_.isString(results)) {
  241. $scope.render(results);
  242. return;
  243. }
  244. $scope.datapointsWarning = false;
  245. $scope.datapointsCount = 0;
  246. $scope.datapointsOutside = false;
  247. var data = _.map(results.data, $scope.seriesHandler);
  248. $scope.datapointsWarning = $scope.datapointsCount || !$scope.datapointsOutside;
  249. $scope.annotationsPromise
  250. .then(function(annotations) {
  251. data.annotations = annotations;
  252. $scope.render(data);
  253. }, function() {
  254. $scope.render(data);
  255. });
  256. };
  257. $scope.seriesHandler = function(seriesData, index) {
  258. var datapoints = seriesData.datapoints;
  259. var alias = seriesData.target;
  260. var color = $scope.panel.aliasColors[alias] || $scope.colors[index];
  261. var yaxis = $scope.panel.aliasYAxis[alias] || 1;
  262. var seriesInfo = {
  263. alias: alias,
  264. color: color,
  265. enable: true,
  266. yaxis: yaxis
  267. };
  268. $scope.legend.push(seriesInfo);
  269. var series = new timeSeries.ZeroFilled({
  270. datapoints: datapoints,
  271. info: seriesInfo,
  272. });
  273. if (datapoints && datapoints.length > 0) {
  274. var last = moment.utc(datapoints[datapoints.length - 1][1] * 1000);
  275. var from = moment.utc($scope.range.from);
  276. if (last - from < -10000) {
  277. $scope.datapointsOutside = true;
  278. }
  279. $scope.datapointsCount += datapoints.length;
  280. }
  281. return series;
  282. };
  283. $scope.add_target = function() {
  284. $scope.panel.targets.push({target: ''});
  285. };
  286. $scope.otherPanelInFullscreenMode = function() {
  287. return $rootScope.fullscreen && !$scope.fullscreen;
  288. };
  289. $scope.render = function(data) {
  290. $scope.$emit('render', data);
  291. };
  292. $scope.changeSeriesColor = function(series, color) {
  293. series.color = color;
  294. $scope.panel.aliasColors[series.alias] = series.color;
  295. $scope.render();
  296. };
  297. $scope.toggleSeries = function(info) {
  298. if ($scope.hiddenSeries[info.alias]) {
  299. delete $scope.hiddenSeries[info.alias];
  300. }
  301. else {
  302. $scope.hiddenSeries[info.alias] = true;
  303. }
  304. $scope.$emit('toggleLegend', info.alias);
  305. };
  306. $scope.toggleYAxis = function(info) {
  307. info.yaxis = info.yaxis === 2 ? 1 : 2;
  308. $scope.panel.aliasYAxis[info.alias] = info.yaxis;
  309. $scope.render();
  310. };
  311. $scope.toggleGridMinMax = function(key) {
  312. $scope.panel.grid[key] = _.toggle($scope.panel.grid[key], null, 0);
  313. $scope.render();
  314. };
  315. });
  316. });