stats.js 5.1 KB

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