fnordmetric 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ };