stats.js 4.9 KB

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