stats.js 4.7 KB

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