stats.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. 'use strict';
  2. angular.module('etcdControlPanel')
  3. .controller('StatsCtrl', function ($scope, $rootScope, $interval, EtcdV2, statsVega) {
  4. $scope.graphContainer = '#latency';
  5. $scope.graphVisibility = 'etcd-graph-show';
  6. $scope.tableVisibility = 'etcd-table-hide';
  7. //make requests
  8. function readStats() {
  9. EtcdV2.getStat('leader').get().success(function(data) {
  10. $scope.leaderStats = data;
  11. $scope.leaderName = data.leader;
  12. $scope.peers = [];
  13. //hardcode leader stats
  14. $scope.peers.push({
  15. latency: {
  16. average: 0,
  17. current: 0,
  18. minimum: 0,
  19. maximum: 0,
  20. standardDeviation: 0
  21. },
  22. name: data.leader
  23. });
  24. $.each(data.followers, function(index, value) {
  25. value.name = index;
  26. $scope.peers.push(value);
  27. });
  28. //sort array so peers don't jump when output
  29. $scope.peers.sort(function(a, b){
  30. if(a.name < b.name) return -1;
  31. if(a.name > b.name) return 1;
  32. return 0;
  33. });
  34. drawGraph();
  35. });
  36. }
  37. function drawGraph () {
  38. //hardcoded padding from chart json
  39. var vertPadding = 30;
  40. var horzPadding = 15;
  41. //fetch width and height of graph area
  42. var width = $($scope.graphContainer).width() - horzPadding;
  43. var height = $($scope.graphContainer).height() - vertPadding;
  44. // parse a spec and create a visualization view
  45. function parse(spec) {
  46. vg.parse.spec(spec, function(chart) {
  47. chart({
  48. el: $scope.graphContainer,
  49. data: {
  50. 'stats': $scope.peers
  51. }
  52. }).width(width).height(height).update();
  53. });
  54. }
  55. parse(statsVega);
  56. }
  57. $scope.showTable = function() {
  58. $scope.tableVisibility = 'etcd-table-reveal';
  59. };
  60. $scope.showGraph = function() {
  61. $scope.tableVisibility = 'etcd-table-hide';
  62. };
  63. $scope.getHeight = function() {
  64. return $(window).height();
  65. };
  66. $scope.getWidth = function() {
  67. return $(window).width();
  68. };
  69. //$scope.$watch($scope.getHeight, function() {
  70. ////$('.etcd-container.etcd-stats .etcd-body').css('height', $scope.getHeight()-5);
  71. //readStats();
  72. //});
  73. $scope.$watch($scope.getWidth, function() {
  74. readStats();
  75. });
  76. window.onresize = function(){
  77. $scope.$apply();
  78. };
  79. $scope.pollPromise = null;
  80. $scope.startPolling = function() {
  81. // Update the graphs live
  82. if ($scope.pollPromise) {
  83. return;
  84. }
  85. $scope.pollPromise = $interval(function() {
  86. readStats();
  87. }, 500);
  88. };
  89. $scope.stopPolling = function() {
  90. $interval.cancel($scope.pollPromise);
  91. $scope.pollPromise = null;
  92. };
  93. // Stop polling when navigating away from a view with this controller.
  94. $rootScope.$on('$routeChangeStart', function () {
  95. $scope.stopPolling();
  96. });
  97. $scope.startPolling();
  98. })
  99. /* statsVega returns the vega configuration for the stats dashboard */
  100. .factory('statsVega', function () {
  101. return {
  102. 'padding': {'top': 10, 'left': 5, 'bottom': 40, 'right': 10},
  103. 'data': [
  104. {
  105. 'name': 'stats'
  106. },
  107. {
  108. 'name': 'thresholds',
  109. 'values': [50, 100]
  110. }
  111. ],
  112. 'scales': [
  113. {
  114. 'name': 'y',
  115. 'type': 'ordinal',
  116. 'range': 'height',
  117. 'domain': {'data': 'stats', 'field': 'index'}
  118. },
  119. {
  120. 'name': 'x',
  121. 'range': 'width',
  122. 'domainMin': 0,
  123. 'domainMax': 100,
  124. 'nice': true,
  125. 'zero': true,
  126. 'domain': {'data': 'stats', 'field': 'data.latency.current'}
  127. },
  128. {
  129. 'name': 'color',
  130. 'type': 'linear',
  131. 'domain': [10, 50, 100, 1000000000],
  132. 'range': ['#00DB24', '#FFC000', '#c40022', '#c40022']
  133. }
  134. ],
  135. 'axes': [
  136. {
  137. 'type': 'x',
  138. 'scale': 'x',
  139. 'ticks': 6,
  140. 'name': 'Latency (ms)'
  141. },
  142. {
  143. 'type': 'y',
  144. 'scale': 'y',
  145. 'properties': {
  146. 'ticks': {
  147. 'stroke': {'value': 'transparent'}
  148. },
  149. 'majorTicks': {
  150. 'stroke': {'value': 'transparent'}
  151. },
  152. 'labels': {
  153. 'fill': {'value': 'transparent'}
  154. },
  155. 'axis': {
  156. 'stroke': {'value': '#333'},
  157. 'strokeWidth': {'value': 1}
  158. }
  159. }
  160. }
  161. ],
  162. 'marks': [
  163. {
  164. 'type': 'rect',
  165. 'from': {'data': 'stats'},
  166. 'properties': {
  167. 'enter': {
  168. 'x': {'scale': 'x', 'value': 0},
  169. 'x2': {'scale': 'x', 'field': 'data.latency.current'},
  170. 'y': {'scale': 'y', 'field': 'index', 'offset': -1},
  171. 'height': {'value': 3},
  172. 'fill': {'scale':'color', 'field':'data.latency.current'}
  173. }
  174. }
  175. },
  176. {
  177. 'type': 'symbol',
  178. 'from': {'data': 'stats'},
  179. 'properties': {
  180. 'enter': {
  181. 'x': {'scale': 'x', 'field': 'data.latency.current'},
  182. 'y': {'scale': 'y', 'field': 'index'},
  183. 'size': {'value': 50},
  184. 'fill': {'value': '#000'}
  185. }
  186. }
  187. }
  188. ]
  189. };
  190. });