fnordmetric 1.0.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/Rakefile +1 -1
  2. data/fnordmetric.gemspec +1 -0
  3. data/lib/fnordmetric.rb +6 -13
  4. data/lib/fnordmetric/acceptors/acceptor.rb +20 -7
  5. data/lib/fnordmetric/acceptors/amqp_acceptor.rb +56 -0
  6. data/lib/fnordmetric/acceptors/fyrehose_acceptor.rb +43 -0
  7. data/lib/fnordmetric/acceptors/stomp_acceptor.rb +71 -0
  8. data/lib/fnordmetric/acceptors/tcp_acceptor.rb +1 -0
  9. data/lib/fnordmetric/acceptors/udp_acceptor.rb +2 -1
  10. data/lib/fnordmetric/context.rb +21 -9
  11. data/lib/fnordmetric/defaults.rb +16 -3
  12. data/lib/fnordmetric/gauge.rb +8 -3
  13. data/lib/fnordmetric/gauge_calculations.rb +8 -2
  14. data/lib/fnordmetric/gauge_modifiers.rb +5 -4
  15. data/lib/fnordmetric/gauges/server_health_gauge.rb +13 -0
  16. data/lib/fnordmetric/namespace.rb +53 -17
  17. data/lib/fnordmetric/util.rb +25 -0
  18. data/lib/fnordmetric/version.rb +1 -1
  19. data/lib/fnordmetric/web/app.rb +7 -66
  20. data/lib/fnordmetric/web/reactor.rb +32 -2
  21. data/lib/fnordmetric/web/websocket.rb +1 -1
  22. data/lib/fnordmetric/widgets/bars_widget.rb +1 -1
  23. data/lib/fnordmetric/widgets/numbers_widget.rb +28 -4
  24. data/lib/fnordmetric/widgets/timeseries_widget.rb +19 -9
  25. data/lib/fnordmetric/widgets/toplist_widget.rb +8 -4
  26. data/lib/fnordmetric/worker.rb +5 -1
  27. data/lib/fnordmetric/zero_config_gauge.rb +138 -0
  28. data/spec/context_spec.rb +4 -4
  29. data/spec/event_spec.rb +11 -11
  30. data/spec/gauge_modifiers_spec.rb +135 -29
  31. data/spec/gauge_spec.rb +7 -2
  32. data/spec/namespace_spec.rb +8 -19
  33. data/spec/util_spec.rb +46 -0
  34. data/web/.gitignore +4 -0
  35. data/web/build.sh +34 -0
  36. data/web/{fnordmetric.css → css/fnordmetric.core.css} +121 -58
  37. data/web/haml/app.haml +4 -22
  38. data/web/{loader.gif → img/loader.gif} +0 -0
  39. data/web/js/fnordmetric.bars_widget.js +3 -3
  40. data/web/js/fnordmetric.dashboard_view.js +1 -1
  41. data/web/js/fnordmetric.gauge_explorer.js +173 -0
  42. data/web/js/fnordmetric.js +93 -33
  43. data/web/js/fnordmetric.numbers_widget.js +15 -14
  44. data/web/js/fnordmetric.session_view.js +0 -1
  45. data/web/js/fnordmetric.timeline_widget.js +3 -3
  46. data/web/js/fnordmetric.timeseries_widget.js +46 -29
  47. data/web/js/fnordmetric.toplist_widget.js +23 -16
  48. data/web/js/fnordmetric.util.js +12 -8
  49. data/web/vendor/font-awesome/css/font-awesome-ie7.min.css +22 -0
  50. data/web/vendor/font-awesome/css/font-awesome.css +522 -221
  51. data/web/vendor/font-awesome/css/font-awesome.min.css +33 -0
  52. data/web/vendor/font-awesome/font/FontAwesome.otf +0 -0
  53. data/web/vendor/font-awesome/font/fontawesome-webfont.eot +0 -0
  54. data/web/vendor/font-awesome/font/fontawesome-webfont.svg +278 -169
  55. data/web/vendor/font-awesome/font/fontawesome-webfont.ttf +0 -0
  56. data/web/vendor/font-awesome/font/fontawesome-webfont.woff +0 -0
  57. data/web/vendor/jquery-ui.min.js +6 -413
  58. data/web/vendor/jquery.combobox.js +129 -0
  59. metadata +55 -48
  60. data/doc/V1.0-ROADMAP +0 -97
  61. data/doc/full_example.rb +0 -224
  62. data/doc/legacy_example.rb +0 -640
  63. data/doc/minimal_example.rb +0 -26
  64. data/doc/preview1.png +0 -0
  65. data/doc/preview2.png +0 -0
  66. data/doc/preview3.png +0 -0
  67. data/readme.md +0 -365
  68. data/web/vendor/d3.v2.js +0 -9382
  69. data/web/vendor/font-awesome/font/fontawesome-webfont.svgz +0 -0
  70. data/web/vendor/rickshaw.css +0 -286
  71. data/web/vendor/rickshaw.fnordmetric.js +0 -2700
@@ -80,7 +80,7 @@ FnordMetric.views.dashboardView = (function(dashboard_name){
80
80
  };
81
81
 
82
82
  function announce(evt){
83
- if((evt.class == "widget_response") || (evt.class == "widget_push")){
83
+ if((evt.type == "widget_response") || (evt.type == "widget_push")){
84
84
  for(wkey in widget_objs){
85
85
  if(widget_objs[wkey].announce){
86
86
  widget_objs[wkey].announce(evt)
@@ -0,0 +1,173 @@
1
+ FnordMetric.views.gaugeExplorer = (function(){
2
+
3
+ var elem, widget, gauge_list, widget_inst;
4
+ var start_timestamp, end_timestamp, time_range;
5
+ var currentGauge;
6
+ var autoupdate_timer, autodiscover_timer;
7
+
8
+ var time_range = 3600;
9
+ var default_time_ranges = [
10
+ ["5m", 300],
11
+ ["15m", 900],
12
+ ["30m", 1800],
13
+ ["1h", 3600],
14
+ ["2h", 3600 * 2],
15
+ ["6h", 3600 * 6],
16
+ ["12h", 3600 * 12],
17
+ ["24h", 3600 * 24],
18
+ ["48h", 3600 * 48]
19
+ ];
20
+
21
+ function load(_elem){
22
+ elem = _elem;
23
+
24
+ elem.html('<div class="navbar"></div><div class="ge_controlpanel">' +
25
+ '<label>Select a Gauge</label><select class="ge_gauge_picker">' +
26
+ '<option selected=selected>Please select a gauge...</option></select>' +
27
+ '<div class="ge_meta">Type to autocomplete...</div>' +
28
+ '</div><div class="ge_controlpanel" style="border-right:none;">' +
29
+ '<label>Select the Timerange</label><a class="button datepicker_sa"><div class="date" style="width:300px;">&nbsp;</div>' +
30
+ '<i class="icon-calendar"></i></a>' +
31
+ '<div class="ge_timerange_links ge_meta">Recent Data: </div></div>' +
32
+ '<div style="clear:both;" class="widget_viewport"><div class="headbar"><h2>Please select a gauge...</h2></div><i class="ge_empty">Please select a gauge...</i></div>');
33
+
34
+ FnordMetric.ui.navbar($('.navbar', elem), {
35
+ breadcrumb: [
36
+ ["Gauge Explorer", "#gauge_explorer"],
37
+ ],
38
+ buttons: [
39
+ ["<i class='icon-refresh'></i>Refresh", function(){ load(elem); }]
40
+ ]
41
+ });
42
+
43
+ $(default_time_ranges).each(function(i, tr){
44
+ $('.ge_timerange_links', elem).append(
45
+ $('<a>')
46
+ .attr('href', '#')
47
+ .attr('data-timerange', tr[1])
48
+ .click(function(){
49
+ time_range = parseInt($(this).attr('data-timerange'), 10);
50
+ autoupdate();
51
+ return false;
52
+ })
53
+ .html(tr[0]));
54
+ });
55
+
56
+ autoupdate();
57
+ render();
58
+ requestGaugeInfoAsync();
59
+
60
+ autodiscover_timer = window.setInterval(requestGaugeInfoAsync, 5000);
61
+ autoupdate_timer = window.setInterval(autoupdate, 1000);
62
+ };
63
+
64
+ function autoupdate() {
65
+ end_timestamp = ((new Date()).getTime() / 1000) + 60;
66
+ start_timestamp = end_timestamp - time_range;
67
+
68
+ if (widget)
69
+ widget.set_timerange(start_timestamp, end_timestamp);
70
+
71
+ $(".datepicker_sa .date", elem).html(
72
+ FnordMetric.util.dateFormat(start_timestamp) +
73
+ '&nbsp;&dash;&nbsp;' +
74
+ FnordMetric.util.dateFormat(end_timestamp)
75
+ )
76
+ }
77
+
78
+ function render() {
79
+ if (!currentGauge) return;
80
+
81
+ $(".widget_viewport", elem).html('');
82
+ widget = FnordMetric.widgets.timeseriesWidget();
83
+
84
+ var gauges = [currentGauge.key];
85
+ var series = [{
86
+ "color": "#4572a7",
87
+ "data": [{x:0, y:0}],
88
+ name: currentGauge.key,
89
+ title: currentGauge.title
90
+ }];
91
+
92
+ var wheight = FnordMetric.get_conf().gauge_explorer_widget_height;
93
+
94
+ if (!wheight)
95
+ wheight = window.innerHeight - 300;
96
+
97
+ widget_inst = widget.render({
98
+ elem: $(".widget_viewport", elem),
99
+ title: currentGauge.title,
100
+ async_chart: true,
101
+ start_timestamp: start_timestamp,
102
+ end_timestamp: end_timestamp,
103
+ include_current: true,
104
+ width: 100,
105
+ height: wheight,
106
+ gauges: gauges,
107
+ series: series,
108
+ default_cardinal: false,
109
+ default_style: "line",
110
+ no_update_range: true,
111
+ no_datepicker: true,
112
+ widget_key: "gauge_explorer"
113
+ });
114
+ }
115
+
116
+ function resize(_width, _height){
117
+ render();
118
+ };
119
+
120
+ function announce(evt){
121
+ if (evt.type == "widget_response" && widget)
122
+ widget.announce(evt);
123
+
124
+ if (evt.type == "gauge_list_response"){
125
+ $('.ge_gauge_picker', elem).html();
126
+ gauge_list = {};
127
+ var changed = false;
128
+
129
+ $(evt.gauges).each(function(n, gauge){
130
+ if (typeof gauge_list[gauge.key] == 'undefined') {
131
+ var gauge_title = gauge.title + ' [' + gauge.key + ']';
132
+
133
+ gauge_list[gauge.key] = {
134
+ "key": gauge.key,
135
+ "title": gauge.title
136
+ };
137
+
138
+ $('.ge_gauge_picker', elem).append(
139
+ '<option value=' + gauge.key + '>' + gauge_title + '</option>');
140
+
141
+ changed = true;
142
+ }
143
+ });
144
+
145
+ if (changed || evt.gauges.length == 0)
146
+ $('.ge_gauge_picker', elem)
147
+ .bind('value_changed', function(){
148
+ currentGauge = gauge_list[$(this).val()];
149
+ render();
150
+ })
151
+ .combobox();
152
+ }
153
+ }
154
+
155
+ function requestGaugeInfoAsync() {
156
+ FnordMetric.publish({
157
+ "type": "gauge_list_request"
158
+ });
159
+ }
160
+
161
+ function close(){
162
+ window.clearInterval(autoupdate_timer);
163
+ window.clearInterval(autodiscover_timer);
164
+ };
165
+
166
+ return {
167
+ load: load,
168
+ resize: resize,
169
+ announce: announce,
170
+ close: close
171
+ };
172
+
173
+ });
@@ -1,8 +1,10 @@
1
- var FnordMetric = (function(){
1
+ var FnordMetric = (function(pre_init){
2
2
 
3
3
  var canvasElem = false;
4
4
  var currentView = false;
5
5
  var currentNamespace = false;
6
+ var ws_addr = null;
7
+ var js_api = false;
6
8
  var gauges = {};
7
9
  var socket, conf;
8
10
 
@@ -26,7 +28,7 @@ var FnordMetric = (function(){
26
28
 
27
29
  return ul;
28
30
  }
29
-
31
+
30
32
  function renderSidebar(){
31
33
  var prev_active = false;
32
34
 
@@ -37,18 +39,23 @@ var FnordMetric = (function(){
37
39
  $('#sidebar')
38
40
  .html('');
39
41
 
40
- /*if(!conf.hide_overview){
41
- renderSidebarGroup('Overview')
42
+ var sidebar_overview;
43
+
44
+ if (!conf.hide_active_users || !conf.hide_gauge_explorer)
45
+ sidebar_overview = renderSidebarGroup('Overview');
46
+
47
+ if (!conf.hide_gauge_explorer) {
48
+ sidebar_overview
42
49
  .append($('<li class="overview">')
43
- .append('<span class="picto piechart">')
44
- .append($('<a href="#" class="title">').html('App Overview')));
45
- }*/
50
+ .append($('<a href="#" class="title">').html('<i class="icon-bar-chart"></i> Gauge Explorer'))
51
+ .click(function(){ renderGaugeExplorer(); }));
52
+ }
46
53
 
47
- if(!conf.hide_active_users){
48
- renderSidebarGroup('Overview')
54
+ if (!conf.hide_active_users) {
55
+ sidebar_overview
49
56
  .append($('<li class="overview">')
50
- .append($('<a href="#" class="title">').html('Active Users'))
51
- .click(function(){ renderSessionView(); }));
57
+ .append($('<a href="#" class="title">').html('<i class="icon icon-group"></i> Active Users'))
58
+ .click(function(){ renderSessionView(); }));
52
59
  }
53
60
 
54
61
  for(gkey in gauges){
@@ -61,7 +68,7 @@ var FnordMetric = (function(){
61
68
  ul.append($('<li class="gauge">')
62
69
  .attr('data-token', gkey)
63
70
  .attr('data-view', gauges[gkey].view_type)
64
- .append('<i class="icon-folder-close">')
71
+ .append('<i class="icon-arrow-right">')
65
72
  .append($('<a href="#" class="title">').html(gauges[gkey].title)));
66
73
  }
67
74
 
@@ -101,10 +108,10 @@ var FnordMetric = (function(){
101
108
  renderSidebar();
102
109
 
103
110
  if(!currentView && (window.location.hash.length < 2)){
104
- sidebarClick.apply($('#sidebar li:first'));
105
- } else if(!navigatedViaHash){
106
- navigateViaHash();
111
+ window.location.hash = "gauge_explorer";
107
112
  }
113
+
114
+ navigateViaHash();
108
115
  }
109
116
  }
110
117
 
@@ -113,6 +120,11 @@ var FnordMetric = (function(){
113
120
  loadView(FnordMetric.views.sessionView());
114
121
  }
115
122
 
123
+ function renderGaugeExplorer(){
124
+ window.location.hash = 'gauge_explorer';
125
+ loadView(FnordMetric.views.gaugeExplorer());
126
+ }
127
+
116
128
  function renderOverviewView(){
117
129
  loadView(FnordMetric.views.overviewView());
118
130
  }
@@ -127,10 +139,13 @@ var FnordMetric = (function(){
127
139
  };
128
140
 
129
141
  function resizeView(){
130
- var viewport_width = window.innerWidth - 220;
131
- if(viewport_width < 780){ viewport_width=780; }
132
- $('#viewport').width(viewport_width);
133
- $('.navbar').width(viewport_width);
142
+ if (!conf.no_resize_viewport) {
143
+ var viewport_width = window.innerWidth - 220;
144
+ if(viewport_width < 780){ viewport_width=780; }
145
+ $('#viewport').width(viewport_width);
146
+ $('.navbar').width(viewport_width);
147
+ }
148
+
134
149
  FnordMetric.ui.resizable('.viewport_inner');
135
150
  if(currentView){
136
151
  currentView.resize(
@@ -144,11 +159,16 @@ var FnordMetric = (function(){
144
159
  $(".resize_listener").trigger('fm_resize');
145
160
  };
146
161
 
147
-
148
162
  function init(_conf){
149
163
  conf = _conf;
150
164
  this.currentNamespace = _conf.token;
151
165
 
166
+ if (conf.address) {
167
+ this.ws_addr = "ws://" + conf.address + '/stream';
168
+ } else {
169
+ this.ws_addr = "ws://" + document.location.host + '/stream';
170
+ }
171
+
152
172
  if(conf.title){ $('title').html(conf.title); }
153
173
 
154
174
  canvasElem = $("<div class='viewport_inner'>");
@@ -161,15 +181,23 @@ var FnordMetric = (function(){
161
181
  connect();
162
182
 
163
183
  $('#app').html(_wrap_elem);
164
- $(window).resize(resizeView);
184
+ $(document).ready(renderSidebar);
185
+ $(window).resize(resizeView);
165
186
  resizeView();
166
187
  };
167
188
 
168
189
  function connect(){
169
- socket = new WebSocket("ws://" + document.location.host + '/stream');
170
- socket.onmessage = socketMessage;
171
- socket.onclose = socketClose;
172
- socket.onopen = socketOpen;
190
+ socket = new WebSocket(FnordMetric.ws_addr);
191
+
192
+ if (js_api == false) {
193
+ socket.onmessage = socketMessage;
194
+ socket.onclose = socketClose;
195
+ socket.onopen = socketOpen;
196
+ } else {
197
+ socket.onmessage = js_api.socketMessage;
198
+ socket.onclose = js_api.socketClose;
199
+ socket.onopen = js_api.socketOpen;
200
+ }
173
201
  }
174
202
 
175
203
  function publish(obj){
@@ -190,13 +218,16 @@ var FnordMetric = (function(){
190
218
  }
191
219
 
192
220
  function socketOpen(){
193
- console.log("connected...");
194
- publish({"type": "discover_request"});
195
- $('.flash_msg_over').fadeOut(function(){ $(this).remove(); });
221
+ console.log("[FnordMetric] connected...");
222
+
223
+ if (!conf.no_discovery)
224
+ publish({"type": "discover_request"});
225
+
226
+ $('.flash_msg_over').fadeOut(function(){ $(this).remove(); });
196
227
  }
197
228
 
198
229
  function socketClose(){
199
- console.log("socket closed");
230
+ console.log("[FnordMetric] socket closed");
200
231
 
201
232
  if($('.flash_msg_over').length == 0){
202
233
  $(viewport)
@@ -211,7 +242,7 @@ var FnordMetric = (function(){
211
242
  }, 20);
212
243
  }
213
244
 
214
- window.setTimeout(connect, 1000);
245
+ window.setTimeout(connect, 1000);
215
246
  }
216
247
 
217
248
  function navigateViaHash(){
@@ -221,6 +252,9 @@ var FnordMetric = (function(){
221
252
  elem = $('#sidebar li.gauge[data-token="'+window.location.hash.slice(11)+'"]');
222
253
  } else if (!!window.location.hash.match(/^#gauge\/[a-zA-Z_0-9-]+$/)){
223
254
  elem = $('#sidebar li.gauge[data-token="'+window.location.hash.slice(7)+'"]');
255
+ } else if(window.location.hash == "#gauge_explorer") {
256
+ navigatedViaHash = true;
257
+ renderGaugeExplorer();
224
258
  } else if(window.location.hash == "#active_users") {
225
259
  navigatedViaHash = true;
226
260
  renderSessionView();
@@ -233,23 +267,49 @@ var FnordMetric = (function(){
233
267
  }
234
268
  }
235
269
 
270
+ var setup = function(opts){
271
+ if (typeof $ == 'undefined') {
272
+ console.log("error: FnordMetric requires jQuery 1.6.2+");
273
+ return;
274
+ }
275
+
276
+ FnordMetric.currentNamespace = opts.namespace;
277
+ FnordMetric.ws_addr = "ws://" + opts.address + "/stream";
278
+
279
+ $(document).ready(function(){
280
+ js_api = FnordMetric.js_api;
281
+ connect();
282
+ });
283
+ }
284
+
285
+ var get_conf = function(){
286
+ return conf;
287
+ }
288
+
236
289
  return {
237
290
  renderDashboard: renderDashboard,
238
291
  renderGauge: renderGauge,
239
292
  renderSessionView: renderSessionView,
240
293
  renderOverviewView: renderOverviewView,
294
+ renderGaugeExplorer: renderGaugeExplorer,
241
295
  resizeView: resizeView,
296
+ loadView: loadView,
242
297
  init: init,
243
298
  publish: publish,
299
+ setup: setup,
244
300
  p: '',
245
301
  socket: socket,
246
- currentNamespace: null,
302
+ currentNamespace: currentNamespace,
303
+ ws_addr: ws_addr,
247
304
  currentWidgetUID: 23,
248
305
  ui: {},
249
306
  views: {},
250
307
  widgets: {},
251
308
  util: {},
252
- gauges: gauges
309
+ gauges: gauges,
310
+ get_conf: get_conf,
311
+ rickshaw: pre_init.rickshaw,
312
+ util: pre_init.util
253
313
  };
254
314
 
255
- })();
315
+ })(FnordMetric);
@@ -15,19 +15,15 @@ FnordMetric.widgets.numbersWidget = function(){
15
15
  });
16
16
 
17
17
  if(!opts.series_titles){
18
- opts.series_titles = {};
18
+ opts.series_titles = opts.series;
19
19
  }
20
20
 
21
21
  for(k in opts.series){
22
22
 
23
- if (!opts.series_titles[opts.series[k]]){
24
- opts.series_titles[opts.series[k]] = opts.series[k];
25
- }
26
-
27
23
  var container = $('<div></div>')
28
24
  .addClass('numbers_container')
29
25
  .attr('rel', opts.series[k])
30
- .append($('<div class="title">').html(opts.series_titles[opts.series[k]]));
26
+ .append($('<div class="title">').html(opts.series_titles[k]));
31
27
 
32
28
  opts.elem.append(container);
33
29
  }
@@ -53,7 +49,7 @@ FnordMetric.widgets.numbersWidget = function(){
53
49
  $('.numbers_container', opts.elem).each(function(i, e){
54
50
  var num_numbers = $('.number', e).length;
55
51
  if(num_numbers > max_per_row){ num_numbers = max_per_row; }
56
- $(e).css('width', (num_numbers * 95)+'px');
52
+ $(e).css('width', (num_numbers * 90)+'px');
57
53
  });
58
54
  }
59
55
 
@@ -62,7 +58,7 @@ FnordMetric.widgets.numbersWidget = function(){
62
58
  FnordMetric.publish({
63
59
  "namespace": FnordMetric.currentNamespace,
64
60
  "type": "widget_request",
65
- "klass": "NumbersWidget",
61
+ "klass": "generic",
66
62
  "channel": opts.channel,
67
63
  "cmd": "values_for",
68
64
  "gauge": opts.series[k],
@@ -86,17 +82,22 @@ FnordMetric.widgets.numbersWidget = function(){
86
82
  .attr('rel', vkey)
87
83
  .append($('<span class="desc">').html(vdesc))
88
84
  .append($('<span class="value">').html(0))
85
+
86
+ if (opts.series_units[series]) {
87
+ velem.attr("data-unit", opts.series_units[series]);
88
+ }
89
+
89
90
  celem.append(velem);
90
91
  }
91
92
 
92
93
  if(!!opts.dont_animate){
93
- velem.attr('data', values[vkey].value)
94
+ velem.attr('data', values[vkey].value)
94
95
  $('.value', velem).html(FnordMetric.util.formatGaugeValue(vkey, values[vkey].value));
95
96
  } else {
96
- velem.attr('data', values[vkey].value)
97
+ velem.attr('data', values[vkey].value)
97
98
  }
98
99
  }
99
-
100
+
100
101
  resize();
101
102
 
102
103
  if(!opts.dont_animate){
@@ -106,8 +107,8 @@ FnordMetric.widgets.numbersWidget = function(){
106
107
 
107
108
  function announce(ev){
108
109
  if(ev.widget_key == opts.widget_key){
109
- if((ev.class == "widget_response") && (ev.cmd == "values_for")){
110
- renderValues(ev.series, ev.values)
110
+ if((ev.type == "widget_response") && (ev.cmd == "values_for")){
111
+ renderValues(ev.gauge, ev.values)
111
112
  }
112
113
  }
113
114
  }
@@ -118,4 +119,4 @@ FnordMetric.widgets.numbersWidget = function(){
118
119
  announce: announce
119
120
  };
120
121
 
121
- };
122
+ };