stats.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. 'use strict';
  2. angular.module('etcdControlPanel')
  3. .controller('StatsCtrl', ['$scope', 'EtcdV2', 'statsVega', function ($scope, 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-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. // Update the graphs live
  80. setInterval(function() {
  81. readStats();
  82. $scope.$apply();
  83. }, 500);
  84. }])
  85. /* statsVega returns the vega configuration for the stats dashboard */
  86. .factory('statsVega', function () {
  87. return {
  88. 'padding': {'top': 10, 'left': 5, 'bottom': 40, 'right': 10},
  89. 'data': [
  90. {
  91. 'name': 'stats'
  92. },
  93. {
  94. 'name': 'thresholds',
  95. 'values': [50, 100]
  96. }
  97. ],
  98. 'scales': [
  99. {
  100. 'name': 'y',
  101. 'type': 'ordinal',
  102. 'range': 'height',
  103. 'domain': {'data': 'stats', 'field': 'index'}
  104. },
  105. {
  106. 'name': 'x',
  107. 'range': 'width',
  108. 'domainMin': 0,
  109. 'domainMax': 100,
  110. 'nice': true,
  111. 'zero': true,
  112. 'domain': {'data': 'stats', 'field': 'data.latency.current'}
  113. },
  114. {
  115. 'name': 'color',
  116. 'type': 'linear',
  117. 'domain': [10, 50, 100, 1000000000],
  118. 'range': ['#00DB24', '#FFC000', '#c40022', '#c40022']
  119. }
  120. ],
  121. 'axes': [
  122. {
  123. 'type': 'x',
  124. 'scale': 'x',
  125. 'ticks': 6,
  126. 'name': 'Latency (ms)'
  127. },
  128. {
  129. 'type': 'y',
  130. 'scale': 'y',
  131. 'properties': {
  132. 'ticks': {
  133. 'stroke': {'value': 'transparent'}
  134. },
  135. 'majorTicks': {
  136. 'stroke': {'value': 'transparent'}
  137. },
  138. 'labels': {
  139. 'fill': {'value': 'transparent'}
  140. },
  141. 'axis': {
  142. 'stroke': {'value': '#333'},
  143. 'strokeWidth': {'value': 1}
  144. }
  145. }
  146. }
  147. ],
  148. 'marks': [
  149. {
  150. 'type': 'rect',
  151. 'from': {'data': 'stats'},
  152. 'properties': {
  153. 'enter': {
  154. 'x': {'scale': 'x', 'value': 0},
  155. 'x2': {'scale': 'x', 'field': 'data.latency.current'},
  156. 'y': {'scale': 'y', 'field': 'index', 'offset': -1},
  157. 'height': {'value': 3},
  158. 'fill': {'scale':'color', 'field':'data.latency.current'}
  159. }
  160. }
  161. },
  162. {
  163. 'type': 'symbol',
  164. 'from': {'data': 'stats'},
  165. 'properties': {
  166. 'enter': {
  167. 'x': {'scale': 'x', 'field': 'data.latency.current'},
  168. 'y': {'scale': 'y', 'field': 'index'},
  169. 'size': {'value': 50},
  170. 'fill': {'value': '#000'}
  171. }
  172. }
  173. }
  174. ]
  175. };
  176. });