fnordmetric 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -0
- data/VERSION +1 -1
- data/doc/preview1.png +0 -0
- data/doc/preview2.png +0 -0
- data/doc/ulm_stats.rb +622 -0
- data/doc/version +1 -0
- data/fnordmetric.gemspec +16 -38
- data/haml/app.haml +12 -5
- data/lib/fnordmetric.rb +3 -0
- data/lib/fnordmetric/app.rb +19 -10
- data/lib/fnordmetric/bars_widget.rb +26 -0
- data/lib/fnordmetric/context.rb +3 -3
- data/lib/fnordmetric/gauge.rb +20 -0
- data/lib/fnordmetric/gauge_calculations.rb +28 -4
- data/lib/fnordmetric/gauge_modifiers.rb +39 -6
- data/lib/fnordmetric/logger.rb +19 -0
- data/lib/fnordmetric/numbers_widget.rb +5 -15
- data/lib/fnordmetric/pie_widget.rb +23 -0
- data/lib/fnordmetric/standalone.rb +1 -1
- data/lib/fnordmetric/timeline_widget.rb +16 -23
- data/lib/fnordmetric/toplist_widget.rb +25 -0
- data/lib/fnordmetric/widget.rb +3 -3
- data/pub/{fnordmetric/fnordmetric.css → fnordmetric.css} +46 -36
- data/pub/fnordmetric.js +1069 -0
- data/pub/loader.gif +0 -0
- data/pub/{highcharts → vendor}/highcharts.js +0 -0
- data/pub/{jquery-1.6.1.min.js → vendor/jquery-1.6.1.min.js} +0 -0
- data/readme.rdoc +228 -311
- data/spec/app_spec.rb +63 -3
- data/spec/gauge_modifiers_spec.rb +157 -2
- data/spec/gauge_spec.rb +143 -12
- data/spec/widget_spec.rb +18 -18
- metadata +33 -58
- data/.document +0 -5
- data/_spec/app_spec.rb +0 -178
- data/_spec/cache_spec.rb +0 -53
- data/_spec/combine_metric_spec.rb +0 -19
- data/_spec/core_spec.rb +0 -50
- data/_spec/count_metric_spec.rb +0 -32
- data/_spec/dashboard_spec.rb +0 -67
- data/_spec/event_spec.rb +0 -46
- data/_spec/metric_spec.rb +0 -118
- data/_spec/report_spec.rb +0 -87
- data/_spec/sum_metric_spec.rb +0 -33
- data/_spec/widget_spec.rb +0 -107
- data/doc/example_server.rb +0 -56
- data/doc/import_dump.rb +0 -26
- data/pub/fnordmetric/fnordmetric.js +0 -543
- data/pub/fnordmetric/widget_numbers.js +0 -71
- data/pub/fnordmetric/widget_timeline.css +0 -0
- data/pub/fnordmetric/widget_timeline.js +0 -110
- data/pub/highcharts/adapters/mootools-adapter.js +0 -12
- data/pub/highcharts/adapters/mootools-adapter.src.js +0 -243
- data/pub/highcharts/adapters/prototype-adapter.js +0 -14
- data/pub/highcharts/adapters/prototype-adapter.src.js +0 -284
- data/pub/highcharts/highcharts.src.js +0 -11103
- data/pub/highcharts/modules/exporting.js +0 -22
- data/pub/highcharts/modules/exporting.src.js +0 -703
- data/pub/highcharts/themes/dark-blue.js +0 -268
- data/pub/highcharts/themes/dark-green.js +0 -268
- data/pub/highcharts/themes/gray.js +0 -262
- data/pub/highcharts/themes/grid.js +0 -97
- data/pub/raphael-min.js +0 -8
- data/pub/raphael-utils.js +0 -221
- data/ulm_stats.rb +0 -198
data/_spec/sum_metric_spec.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require ::File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
-
|
3
|
-
describe FnordMetric::SumMetric do
|
4
|
-
|
5
|
-
before(:each) do
|
6
|
-
FnordMetric::Event.destroy_all
|
7
|
-
FnordMetric.track('a_event_type', :time => 33.hours.ago, :myval => 4)
|
8
|
-
FnordMetric.track('a_event_type', :time => 32.hours.ago, :myval => 2)
|
9
|
-
FnordMetric.track('a_event_type', :time => 28.hours.ago, :myval => 9)
|
10
|
-
FnordMetric.track('a_event_type', :time => 27.hours.ago, :myval => 1)
|
11
|
-
FnordMetric.track('a_event_type', :time => 26.hours.ago, :myval => 6)
|
12
|
-
FnordMetric.track('a_event_type', :time => 13.hours.ago, :myval => 3)
|
13
|
-
FnordMetric.track('a_event_type', :time => 12.hours.ago, :myval => 8)
|
14
|
-
FnordMetric.track('a_event_type', :time => 11.hours.ago, :myval => 7)
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should sum events until now" do
|
18
|
-
metric = FnordMetric.metric('a_event_count', :sum => :myval, :types => [:a_event_type])
|
19
|
-
metric.current.should == 40
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should sum events until 18 hours ago" do
|
23
|
-
metric = FnordMetric.metric('a_event_count', :sum => :myval, :types => [:a_event_type])
|
24
|
-
metric.at(18.hours.ago).should == 22
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should sum events from 30 to 20 hours ago" do
|
28
|
-
metric = FnordMetric.metric('a_event_count', :sum => :myval, :types => [:a_event_type])
|
29
|
-
metric.at(30.hours.ago..20.hours.ago).should == 16
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
end
|
data/_spec/widget_spec.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
require ::File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
-
|
3
|
-
describe FnordMetric::Widget do
|
4
|
-
|
5
|
-
before(:each) do
|
6
|
-
FnordMetric::Event.destroy_all
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should remembe it's own title" do
|
10
|
-
widget = FnordMetric::Widget.new(:title => "My Widget")
|
11
|
-
widget.title.should == "My Widget"
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should add the report on init" do
|
15
|
-
FnordMetric.metric(:my_metric, :sum => :my_field)
|
16
|
-
report = FnordMetric.report(:range => (4.days.ago..Time.now))
|
17
|
-
widget = FnordMetric::Widget.new(:report => report)
|
18
|
-
widget.report.should == report
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should add the report after init" do
|
22
|
-
FnordMetric.metric(:my_metric, :sum => :my_field)
|
23
|
-
report = FnordMetric.report(:range => (4.days.ago..Time.now))
|
24
|
-
widget = FnordMetric::Widget.new
|
25
|
-
widget.report.should be_nil
|
26
|
-
widget.add_report(report)
|
27
|
-
widget.report.should == report
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should define a new widget when given two metric-token" do
|
31
|
-
FnordMetric.metric(:first_metric, :count => :true)
|
32
|
-
FnordMetric.metric(:second_metric, :count => :true)
|
33
|
-
widget = FnordMetric::Widget.new(:metrics => [:first_metric, :second_metric], :title => "My Widget", :type => :timeline)
|
34
|
-
widget.metrics.length.should == 2
|
35
|
-
widget.metrics.first.should be_a(FnordMetric::CountMetric)
|
36
|
-
widget.metrics.first.token.should == :first_metric
|
37
|
-
widget.metrics.last.should be_a(FnordMetric::CountMetric)
|
38
|
-
widget.metrics.last.token.should == :second_metric
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should define a new widget when given two metrics" do
|
42
|
-
my_metrics = [
|
43
|
-
FnordMetric.metric(:first_metric, :count => :true),
|
44
|
-
FnordMetric.metric(:second_metric, :count => :true)
|
45
|
-
]
|
46
|
-
widget = FnordMetric::Widget.new(:metrics => my_metrics, :title => "My Widget", :type => :timeline)
|
47
|
-
widget.metrics.length.should == 2
|
48
|
-
widget.metrics.first.should be_a(FnordMetric::CountMetric)
|
49
|
-
widget.metrics.first.token.should == :first_metric
|
50
|
-
widget.metrics.last.should be_a(FnordMetric::CountMetric)
|
51
|
-
widget.metrics.last.token.should == :second_metric
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should return the right ticks for 1h intervals" do
|
55
|
-
t = Time.now
|
56
|
-
widget = FnordMetric::Widget.new(:range => (t-2.days)..t, :tick => 1.hour)
|
57
|
-
widget.ticks.length.should == 49
|
58
|
-
ranges_should_match! widget.ticks.first, ((t-48.hours)..(t-47.hours))
|
59
|
-
ranges_should_match! widget.ticks.last, (t..(t+1.hour))
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should generate a default range for daily graphs" do
|
63
|
-
widget = FnordMetric::Widget.new(:tick => 1.day)
|
64
|
-
Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
|
65
|
-
widget.default_range.first.should == Time.utc(1991,12,15,00,00,00)
|
66
|
-
widget.default_range.last.should == Time.utc(1992,1,13,23,59,59)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should generate ticks with default range for daily graphs" do
|
71
|
-
widget = FnordMetric::Widget.new(:tick => 1.day)
|
72
|
-
Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
|
73
|
-
widget.ticks.length.should == 30
|
74
|
-
widget.ticks.first.first.utc.should == Time.utc(1991,12,15,00,00,00)
|
75
|
-
widget.ticks.first.last.utc.should == Time.utc(1991,12,16,00,00,00)
|
76
|
-
widget.ticks.last.first.utc.should == Time.utc(1992,1,13,0,0,0)
|
77
|
-
widget.ticks.last.last.utc.should == Time.utc(1992,1,14,0,0,0)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should generate a default range for hourly graphs" do
|
82
|
-
widget = FnordMetric::Widget.new(:tick => 1.hour)
|
83
|
-
Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
|
84
|
-
widget.default_range.first.should == Time.utc(1992,1,12,19,00,00)
|
85
|
-
widget.default_range.last.should == Time.utc(1992,1,13,18,59,59)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
it "should generate a default range for hourly graphs" do
|
90
|
-
widget = FnordMetric::Widget.new(:tick => 1.hour)
|
91
|
-
Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
|
92
|
-
widget.ticks.length.should == 24
|
93
|
-
widget.ticks.first.first.utc.should == Time.utc(1992,1,12,19,00,00)
|
94
|
-
widget.ticks.first.last.utc.should == Time.utc(1992,1,12,20,00,00)
|
95
|
-
widget.ticks.last.first.utc.should == Time.utc(1992,1,13,18,0,0)
|
96
|
-
widget.ticks.last.last.utc.should == Time.utc(1992,1,13,19,00,00)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
private
|
101
|
-
|
102
|
-
def ranges_should_match!(a, b)
|
103
|
-
(a.first.to_i - b.first.to_i).should == 0
|
104
|
-
(a.last.to_i - b.last.to_i).should == 0
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
data/doc/example_server.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
$: << ::File.expand_path('../../lib', __FILE__)
|
2
|
-
|
3
|
-
require "rubygems"
|
4
|
-
require "fnordmetric"
|
5
|
-
require "thin"
|
6
|
-
|
7
|
-
FnordMetric.metric(:passengers_total, :count => true, :types => [:car_seen])
|
8
|
-
FnordMetric.metric(:blubbs, :sum => :passengers, :types => [:car_seen])
|
9
|
-
FnordMetric.metric(:passengers_red_car, :sum => :passengers, :filter => { :colors => :red }, :types => [:car_seen])
|
10
|
-
FnordMetric.metric(:passengers_blue_car, :sum => :passengers, :filter => { :colors => :blue }, :types => [:car_seen])
|
11
|
-
|
12
|
-
FnordMetric.metric(:blue_to_red_ratio, :combine => lambda{ |x|
|
13
|
-
x.passengers_blue_car / x.passengers_red_car
|
14
|
-
})
|
15
|
-
|
16
|
-
|
17
|
-
FnordMetric.dashboard 'Passengers' do |passengers|
|
18
|
-
|
19
|
-
passengers.add_widget FnordMetric.widget(:passengers_total_timeline,
|
20
|
-
:metrics => :passengers_total,
|
21
|
-
:tick => 4.minutes,
|
22
|
-
:title => "Passengers total",
|
23
|
-
:type => :timeline
|
24
|
-
)
|
25
|
-
|
26
|
-
passengers.add_widget FnordMetric.widget(:passenger_blue_red_timeline,
|
27
|
-
:metrics => [:passengers_blue_car, :passengers_red_car],
|
28
|
-
:title => "Passengers (red/blue)",
|
29
|
-
:type => :timeline
|
30
|
-
)
|
31
|
-
|
32
|
-
passengers.add_widget FnordMetric.widget(:passenger_br_ratio_timeline,
|
33
|
-
:metrics => :blue_to_red_ratio,
|
34
|
-
:title => "Passenger blue/red Ratio",
|
35
|
-
:type => :timeline
|
36
|
-
)
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
FnordMetric.dashboard 'Cars & Bikes' do |cars|
|
41
|
-
|
42
|
-
cars.add_widget FnordMetric.widget(:passenger_br_ratio_timeline,
|
43
|
-
:metrics => :blue_to_red_ratio,
|
44
|
-
:title => "Passenger blue/red Ratio",
|
45
|
-
:type => :timeline
|
46
|
-
)
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
|
-
Mongoid.configure do |c|
|
52
|
-
c.master = Mongo::Connection.new.db("myfnordmetric")
|
53
|
-
end
|
54
|
-
|
55
|
-
app = FnordMetric::App.new
|
56
|
-
Thin::Server.start('127.0.0.1', 2323, app)
|
data/doc/import_dump.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require "rubygems"
|
2
|
-
require "redis"
|
3
|
-
require "json"
|
4
|
-
|
5
|
-
if ARGV.length != 1
|
6
|
-
puts "usage: #{$0} /path/to/dump.json"
|
7
|
-
exit!
|
8
|
-
end
|
9
|
-
|
10
|
-
file_path = ARGV[0]
|
11
|
-
|
12
|
-
puts "opening #{file_path}"
|
13
|
-
file = File.open(file_path)
|
14
|
-
|
15
|
-
puts "reading file..."
|
16
|
-
events = file.read.split("\n")
|
17
|
-
|
18
|
-
puts "pushing #{events.length} events to redis"
|
19
|
-
redis = Redis.new
|
20
|
-
total_events = events.length
|
21
|
-
events.each_with_index do |event,n|
|
22
|
-
my_uuid = rand(9999999999999999999).to_s # generate a unique event id ;)
|
23
|
-
redis.lpush("fnordmetric-queue", my_uuid)
|
24
|
-
redis.set("fnordmetric-event-#{my_uuid}", event)
|
25
|
-
puts "#{n}/#{total_events}" if (n%100==0)
|
26
|
-
end
|
@@ -1,543 +0,0 @@
|
|
1
|
-
var FnordMetric = (function(){
|
2
|
-
|
3
|
-
var canvasElem = false;
|
4
|
-
|
5
|
-
var currentNamespace = false;
|
6
|
-
var currentView = false;
|
7
|
-
|
8
|
-
function decPrint(val){
|
9
|
-
return (val < 10 ? '0'+val : val);
|
10
|
-
}
|
11
|
-
|
12
|
-
function formatTimeOfDay(_time){
|
13
|
-
var time = new Date();
|
14
|
-
time.setTime(_time*1000);
|
15
|
-
return decPrint(time.getHours()) + ':' +
|
16
|
-
decPrint(time.getMinutes()) + ':' +
|
17
|
-
decPrint(time.getSeconds());
|
18
|
-
}
|
19
|
-
|
20
|
-
function formatTimeSince(time){
|
21
|
-
var now = new Date().getTime()/1000;
|
22
|
-
var since = now - time;
|
23
|
-
if(since < 60){
|
24
|
-
return parseInt(since) + 's';
|
25
|
-
} else if(since<3600){
|
26
|
-
return parseInt(since/60) + 'm';
|
27
|
-
} else if(since<(3600*24)){
|
28
|
-
return parseInt(since/3600) + 'h';
|
29
|
-
} else {
|
30
|
-
return ">1d"
|
31
|
-
}
|
32
|
-
}
|
33
|
-
|
34
|
-
var numbersWidget = function(opts){
|
35
|
-
|
36
|
-
function render(){
|
37
|
-
//console.log(opts);
|
38
|
-
}
|
39
|
-
|
40
|
-
return {
|
41
|
-
render: render
|
42
|
-
};
|
43
|
-
|
44
|
-
};
|
45
|
-
|
46
|
-
var timelineWidget = function(opts){
|
47
|
-
|
48
|
-
function render(){
|
49
|
-
|
50
|
-
var labels = opts.labels;
|
51
|
-
var series = opts.series;
|
52
|
-
|
53
|
-
var elem_id = "fm_graph_"+parseInt(Math.random()*99999);
|
54
|
-
var elem_inner = $('.inner', opts.elem);
|
55
|
-
elem_inner.append($('<div id="'+elem_id+'"></div>'));
|
56
|
-
|
57
|
-
var width = elem_inner.width();
|
58
|
-
var height = 240;
|
59
|
-
var canvas = Raphael(elem_id, width, height+30);
|
60
|
-
var xtick = width / (labels.length-1);
|
61
|
-
|
62
|
-
var label_mod = Math.ceil((labels.length/10));
|
63
|
-
|
64
|
-
if(opts.independent_y_axis){
|
65
|
-
var max = false;
|
66
|
-
} else {
|
67
|
-
var amax = [];
|
68
|
-
$(series).each(function(n,_series){
|
69
|
-
amax.push(Math.max.apply(Math, _series.data));
|
70
|
-
});
|
71
|
-
var max = Math.max.apply(Math, amax);
|
72
|
-
}
|
73
|
-
|
74
|
-
$(series).each(function(n,_series){
|
75
|
-
|
76
|
-
//var path_string = "M0,"+height;
|
77
|
-
var path_string = "";
|
78
|
-
var _max = max;
|
79
|
-
|
80
|
-
if(!_max){ _max = Math.max.apply(Math, _series.data); }
|
81
|
-
|
82
|
-
_max = _max * 1.1;
|
83
|
-
|
84
|
-
$(_series.data).each(function(i,v){
|
85
|
-
|
86
|
-
var p_x = (i*xtick);
|
87
|
-
var p_y = (height-((v/_max)*height));
|
88
|
-
|
89
|
-
path_string += ( ( i == 0 ? "M" : "L" ) + p_x + ',' + p_y );
|
90
|
-
|
91
|
-
if(i%label_mod==0){
|
92
|
-
canvas.text(p_x, height+10, labels[i]).attr({
|
93
|
-
font: '10px Helvetica, Arial',
|
94
|
-
fill: "#777"
|
95
|
-
});
|
96
|
-
}
|
97
|
-
|
98
|
-
canvas.circle(p_x, p_y, 4).attr({
|
99
|
-
fill: _series.color,
|
100
|
-
stroke: '#fff',
|
101
|
-
"stroke-width": 1,
|
102
|
-
}).toBack();
|
103
|
-
|
104
|
-
|
105
|
-
var htrgt = canvas.rect(p_x - 20, p_y - 20, 40, 40).attr({
|
106
|
-
stroke: "none",
|
107
|
-
fill: "#fff",
|
108
|
-
opacity: 0
|
109
|
-
}).toFront();
|
110
|
-
|
111
|
-
(function(htrgt){
|
112
|
-
|
113
|
-
var t_y = p_y + 9;
|
114
|
-
var ttt = canvas.text(p_x, t_y+10, v).attr({
|
115
|
-
font: '12px Helvetica, Arial',
|
116
|
-
fill: "#fff",
|
117
|
-
opacity: 0
|
118
|
-
});
|
119
|
-
|
120
|
-
var tttb = ttt.getBBox();
|
121
|
-
var ttw = tttb.width+20;
|
122
|
-
var tt = canvas.rect(p_x-(ttw/2), t_y, ttw, 22, 5).attr({
|
123
|
-
stroke: "none",
|
124
|
-
fill: "#000",
|
125
|
-
opacity: 0
|
126
|
-
}).toBack();
|
127
|
-
|
128
|
-
|
129
|
-
$(htrgt[0]).hover(function(){
|
130
|
-
tt.animate({ opacity: 0.8 }, 300);
|
131
|
-
ttt.animate({ opacity: 0.8 }, 300);
|
132
|
-
}, function(){
|
133
|
-
tt.animate({ opacity: 0 }, 300);
|
134
|
-
ttt.animate({ opacity: 0 }, 300);
|
135
|
-
});
|
136
|
-
|
137
|
-
})(htrgt);
|
138
|
-
|
139
|
-
});
|
140
|
-
|
141
|
-
if(_max>0){
|
142
|
-
|
143
|
-
canvas.path(path_string).attr({
|
144
|
-
stroke: _series.color,
|
145
|
-
"stroke-width": 3,
|
146
|
-
"stroke-linejoin": 'round'
|
147
|
-
}).toBack();
|
148
|
-
|
149
|
-
path_string += "L"+width+","+height+" L0,"+height+" Z";
|
150
|
-
|
151
|
-
canvas.path(path_string).attr({
|
152
|
-
stroke: "none",
|
153
|
-
fill: _series.color,
|
154
|
-
opacity: 0.1
|
155
|
-
}).toBack();
|
156
|
-
|
157
|
-
}
|
158
|
-
|
159
|
-
|
160
|
-
});
|
161
|
-
|
162
|
-
canvas.drawGrid(0, 0, width, height, 1, 6, "#ececec");
|
163
|
-
|
164
|
-
}
|
165
|
-
|
166
|
-
return {
|
167
|
-
render: render
|
168
|
-
};
|
169
|
-
|
170
|
-
};
|
171
|
-
|
172
|
-
var sessionView = (function(){
|
173
|
-
|
174
|
-
var listElem = $('<ul class="session_list"></ul>');
|
175
|
-
var feedInnerElem = $('<ul class="feed_inner"></ul>');
|
176
|
-
var typeListElem = $('<ul class="event_type_list"></ul>');
|
177
|
-
var filterElem = $('<div class="events_sidebar"></div>').html(
|
178
|
-
$('<div class="headbar"></div>').html('Event Types')
|
179
|
-
).append(typeListElem);
|
180
|
-
var feedElem = $('<div class="sessions_feed"></div>').html(
|
181
|
-
$('<div class="headbar"></div>').html('Event Feed')
|
182
|
-
).append(feedInnerElem);
|
183
|
-
var sideElem = $('<div class="sessions_sidebar"></div>').html(
|
184
|
-
$('<div class="headbar"></div>').html('Active Users')
|
185
|
-
).append(listElem);
|
186
|
-
|
187
|
-
var eventsPolledUntil = false;
|
188
|
-
var eventsFilter = [];
|
189
|
-
var sessionData = {};
|
190
|
-
var pollRunning = true;
|
191
|
-
|
192
|
-
function load(elem){
|
193
|
-
eventsPolledUntil = parseInt(new Date().getTime()/10000);
|
194
|
-
elem.html('')
|
195
|
-
.append(filterElem)
|
196
|
-
.append(feedElem)
|
197
|
-
.append(sideElem);
|
198
|
-
startPoll();
|
199
|
-
loadEventTypes();
|
200
|
-
};
|
201
|
-
|
202
|
-
function resize(_width, _height){
|
203
|
-
$('.sessions_feed').width(_width-452);
|
204
|
-
};
|
205
|
-
|
206
|
-
function startPoll(){
|
207
|
-
(doSessionPoll())();
|
208
|
-
(doEventsPoll())();
|
209
|
-
sessionView.session_poll = window.setInterval(doSessionPoll(), 1000);
|
210
|
-
};
|
211
|
-
|
212
|
-
function stopPoll(){
|
213
|
-
pollRunning = false;
|
214
|
-
window.clearInterval(sessionView.session_poll);
|
215
|
-
}
|
216
|
-
|
217
|
-
function doSessionPoll(){
|
218
|
-
return (function(){
|
219
|
-
$.ajax({
|
220
|
-
url: '/'+currentNamespace+'/sessions',
|
221
|
-
success: callbackSessionPoll()
|
222
|
-
});
|
223
|
-
});
|
224
|
-
};
|
225
|
-
|
226
|
-
function loadEventHistory(event_type){
|
227
|
-
feedInnerElem.html('');
|
228
|
-
$.ajax({
|
229
|
-
url: '/'+currentNamespace+'/events?type='+event_type,
|
230
|
-
success: function(_data, _status){
|
231
|
-
var data = JSON.parse(_data).events;
|
232
|
-
for(var n=data.length; n >= 0; n--){
|
233
|
-
if(data[n]){ renderEvent(data[n]); }
|
234
|
-
}
|
235
|
-
}
|
236
|
-
});
|
237
|
-
}
|
238
|
-
|
239
|
-
function callbackSessionPoll(){
|
240
|
-
return (function(_data, _status){
|
241
|
-
$.each(JSON.parse(_data).sessions, function(i,v){
|
242
|
-
updateSession(v);
|
243
|
-
});
|
244
|
-
sortSessions();
|
245
|
-
});
|
246
|
-
};
|
247
|
-
|
248
|
-
function loadEventTypes(){
|
249
|
-
$.ajax({
|
250
|
-
url: '/'+currentNamespace+'/event_types',
|
251
|
-
success: function(_data){
|
252
|
-
var data = JSON.parse(_data);
|
253
|
-
$(data.types).each(function(i,v){
|
254
|
-
if(v.slice(0,5)!='_set_'){ addEventType(v,v); }
|
255
|
-
});
|
256
|
-
}
|
257
|
-
});
|
258
|
-
};
|
259
|
-
|
260
|
-
function addEventType(type, display){
|
261
|
-
typeListElem.append(
|
262
|
-
$('<li class="event_type"></li>').append(
|
263
|
-
$('<span class="history"></span>').html('history')
|
264
|
-
.click(function(){
|
265
|
-
$('.event_type_list .event_type input').attr('checked', false);
|
266
|
-
$('input', $(this).parent()).attr('checked', true);
|
267
|
-
updateEventFilter(); loadEventHistory(type);
|
268
|
-
})
|
269
|
-
).append(
|
270
|
-
$('<input type="checkbox" />').attr('checked', true)
|
271
|
-
.click(function(){ updateEventFilter(); })
|
272
|
-
).append(
|
273
|
-
$('<span></span>').html(display)
|
274
|
-
).attr('rel', type)
|
275
|
-
);
|
276
|
-
}
|
277
|
-
|
278
|
-
function updateEventFilter(){
|
279
|
-
var _unchecked_types = [];
|
280
|
-
$('ul.event_type_list li.event_type').each(function(i,v){
|
281
|
-
if(!$('input', v).attr('checked')){
|
282
|
-
_unchecked_types.push($(v).attr('rel'));
|
283
|
-
}
|
284
|
-
});
|
285
|
-
eventsFilter = _unchecked_types;
|
286
|
-
}
|
287
|
-
|
288
|
-
function doEventsPoll(){
|
289
|
-
return (function(){
|
290
|
-
$.ajax({
|
291
|
-
url: '/'+currentNamespace+'/events?since='+eventsPolledUntil,
|
292
|
-
success: callbackEventsPoll()
|
293
|
-
});
|
294
|
-
});
|
295
|
-
};
|
296
|
-
|
297
|
-
function callbackEventsPoll(){
|
298
|
-
return (function(_data, _status){
|
299
|
-
var data = JSON.parse(_data)
|
300
|
-
var events = data.events;
|
301
|
-
var timout = 1000;
|
302
|
-
var maxevents = 200;
|
303
|
-
if(events.length > 0){
|
304
|
-
timeout = 200;
|
305
|
-
eventsPolledUntil = parseInt(events[0]._time)-1;
|
306
|
-
}
|
307
|
-
for(var n=events.length-1; n >= 0; n--){
|
308
|
-
var v = events[n];
|
309
|
-
if(eventsFilter.indexOf(v._type) == -1){
|
310
|
-
if(parseInt(v._time)<=eventsPolledUntil){
|
311
|
-
renderEvent(v);
|
312
|
-
}
|
313
|
-
}
|
314
|
-
};
|
315
|
-
var elems = $("p", feedInnerElem);
|
316
|
-
for(var n=maxevents; n < elems.length; n++){
|
317
|
-
$(elems[n]).remove();
|
318
|
-
}
|
319
|
-
if(pollRunning){
|
320
|
-
window.setTimeout(doEventsPoll(), timout);
|
321
|
-
}
|
322
|
-
});
|
323
|
-
};
|
324
|
-
|
325
|
-
function updateSession(session_data){
|
326
|
-
sessionData[session_data.session_key] = session_data;
|
327
|
-
renderSession(session_data);
|
328
|
-
}
|
329
|
-
|
330
|
-
function sortSessions(){
|
331
|
-
console.log("fixme: sort and splice to 100");
|
332
|
-
}
|
333
|
-
|
334
|
-
function renderSession(session_data){
|
335
|
-
|
336
|
-
var session_name = session_data["_name"];
|
337
|
-
var session_time = formatTimeSince(session_data["_updated_at"]);
|
338
|
-
var session_elem = $('li[data-session='+session_data["session_key"]+']:first');
|
339
|
-
|
340
|
-
if(session_elem.length>0){
|
341
|
-
|
342
|
-
if(session_data["_picture"] && (session_data["_picture"].length > 1)){
|
343
|
-
$('.picture img', session_elem).attr('src', session_data["_picture"])
|
344
|
-
}
|
345
|
-
|
346
|
-
if(session_name){
|
347
|
-
$('.name', session_elem).html(session_name);
|
348
|
-
}
|
349
|
-
|
350
|
-
$('.time', session_elem).html(session_time);
|
351
|
-
|
352
|
-
} else {
|
353
|
-
|
354
|
-
var session_picture = $('<img width="18" />');
|
355
|
-
|
356
|
-
if(!session_name){
|
357
|
-
session_name = session_data["session_key"].substr(0,15)
|
358
|
-
};
|
359
|
-
|
360
|
-
if(session_data["_picture"]){
|
361
|
-
session_picture.attr('src', session_data["_picture"]);
|
362
|
-
};
|
363
|
-
|
364
|
-
listElem.append(
|
365
|
-
$('<li class="session"></li>').append(
|
366
|
-
$('<div class="picture"></div>').html(session_picture)
|
367
|
-
).append(
|
368
|
-
$('<span class="name"></span>').html(session_name)
|
369
|
-
).append(
|
370
|
-
$('<span class="time"></span>').html(session_time)
|
371
|
-
).attr('data-session', session_data["session_key"])
|
372
|
-
);
|
373
|
-
|
374
|
-
}
|
375
|
-
};
|
376
|
-
|
377
|
-
function renderEvent(event_data){
|
378
|
-
var event_time = $('<span class="time"></span>');
|
379
|
-
var event_message = $('<span class="message"></span>');
|
380
|
-
var event_props = $('<span class="properties"></span>');
|
381
|
-
var event_picture = $('<div class="picture"></picture>');
|
382
|
-
|
383
|
-
var event_type = event_data._type;
|
384
|
-
|
385
|
-
if(!event_type){ return true; }
|
386
|
-
|
387
|
-
if(event_data._message){
|
388
|
-
event_message.html(event_data._message);
|
389
|
-
} else if(event_type=="_pageview"){
|
390
|
-
event_message.html("Pageview: " + event_data.url);
|
391
|
-
} else if(event_type.substr(0,5) == '_set_'){
|
392
|
-
return true; /* dont render */
|
393
|
-
} else {
|
394
|
-
event_message.html(event_type);
|
395
|
-
}
|
396
|
-
|
397
|
-
event_time.html(formatTimeOfDay(event_data._time));
|
398
|
-
|
399
|
-
if(event_data._session_key && event_data._session_key.length > 0){
|
400
|
-
if(session_data=sessionData[event_data._session_key]){
|
401
|
-
if(session_data._name){
|
402
|
-
event_props.append(
|
403
|
-
$('<strong></strong>').html(session_data._name)
|
404
|
-
);
|
405
|
-
}
|
406
|
-
if(session_data._picture){
|
407
|
-
event_picture.append(
|
408
|
-
$('<img width="40" />').attr('src', session_data._picture)
|
409
|
-
)
|
410
|
-
}
|
411
|
-
}
|
412
|
-
}
|
413
|
-
|
414
|
-
feedInnerElem.prepend(
|
415
|
-
$('<li class="feed_event"></li>')
|
416
|
-
.append(event_time)
|
417
|
-
.append(event_picture)
|
418
|
-
.append(event_message)
|
419
|
-
.append(event_props)
|
420
|
-
);
|
421
|
-
}
|
422
|
-
|
423
|
-
function close(){
|
424
|
-
stopPoll();
|
425
|
-
};
|
426
|
-
|
427
|
-
return {
|
428
|
-
load: load,
|
429
|
-
resize: resize,
|
430
|
-
close: close
|
431
|
-
};
|
432
|
-
|
433
|
-
});
|
434
|
-
|
435
|
-
|
436
|
-
var dashboardView = (function(dashboard_name){
|
437
|
-
|
438
|
-
var widgets = [];
|
439
|
-
var viewport = null;
|
440
|
-
|
441
|
-
function load(_viewport){
|
442
|
-
viewport = _viewport.html('');
|
443
|
-
/*alert('yay, new dashboard view loaded: ' + dashboard_name);*/
|
444
|
-
$.ajax({
|
445
|
-
url: '/'+currentNamespace+'/dashboard/'+dashboard_name,
|
446
|
-
success: function(resp, status){
|
447
|
-
var conf = JSON.parse(resp);
|
448
|
-
renderWidgets(conf.widgets);
|
449
|
-
}
|
450
|
-
});
|
451
|
-
};
|
452
|
-
|
453
|
-
function renderWidgets(_widgets){
|
454
|
-
for(wkey in _widgets){
|
455
|
-
var widget = _widgets[wkey];
|
456
|
-
widget["elem"] = $('<div class="widget"></div>').append(
|
457
|
-
$('<div class="headbar"></div>').html(widget.title)
|
458
|
-
).append(
|
459
|
-
$('<div class="inner"></div>')
|
460
|
-
);
|
461
|
-
widgets[wkey] = widget;
|
462
|
-
viewport.append(widget.elem);
|
463
|
-
resizeWidget(wkey);
|
464
|
-
renderWidget(wkey);
|
465
|
-
};
|
466
|
-
resize();
|
467
|
-
};
|
468
|
-
|
469
|
-
function renderWidget(wkey){
|
470
|
-
var widget = widgets[wkey];
|
471
|
-
/* argh... */
|
472
|
-
if(widget.klass=='TimelineWidget'){ timelineWidget(widget).render(); }
|
473
|
-
if(widget.klass=='NumbersWidget'){ numbersWidget(widget).render(); }
|
474
|
-
};
|
475
|
-
|
476
|
-
function resizeWidget(wkey){
|
477
|
-
var widget = widgets[wkey];
|
478
|
-
var wwperc = widgets[wkey].width;
|
479
|
-
if(!wwperc){ wwperc = 100; }
|
480
|
-
var wwidth = viewport.width() * (wwperc/100.0);
|
481
|
-
if(wwperc==100){
|
482
|
-
widgets[wkey].elem.addClass('full_width');
|
483
|
-
} else { wwidth -= 1; }
|
484
|
-
widget.elem.width(wwidth);
|
485
|
-
}
|
486
|
-
|
487
|
-
function resize(){
|
488
|
-
for(wkey in widgets){
|
489
|
-
resizeWidget(wkey);
|
490
|
-
};
|
491
|
-
};
|
492
|
-
|
493
|
-
function close(){
|
494
|
-
|
495
|
-
};
|
496
|
-
|
497
|
-
return {
|
498
|
-
load: load,
|
499
|
-
resize: resize,
|
500
|
-
close: close
|
501
|
-
};
|
502
|
-
|
503
|
-
});
|
504
|
-
|
505
|
-
|
506
|
-
function renderDashboard(_dash){
|
507
|
-
loadView(dashboardView(_dash));
|
508
|
-
};
|
509
|
-
|
510
|
-
function renderSessionView(){
|
511
|
-
loadView(sessionView());
|
512
|
-
}
|
513
|
-
|
514
|
-
function loadView(_view){
|
515
|
-
if(currentView){ currentView.close(); }
|
516
|
-
canvasElem.html('loading!');
|
517
|
-
currentView = _view;
|
518
|
-
currentView.load(canvasElem);
|
519
|
-
resizeView();
|
520
|
-
};
|
521
|
-
|
522
|
-
function resizeView(){
|
523
|
-
currentView.resize(
|
524
|
-
canvasElem.innerWidth(),
|
525
|
-
canvasElem.innerHeight()
|
526
|
-
);
|
527
|
-
};
|
528
|
-
|
529
|
-
function init(_namespace, _canvasElem){
|
530
|
-
canvasElem = _canvasElem;
|
531
|
-
currentNamespace = _namespace;
|
532
|
-
loadView(sessionView());
|
533
|
-
};
|
534
|
-
|
535
|
-
return {
|
536
|
-
p: '/fnordmetric/',
|
537
|
-
renderDashboard: renderDashboard,
|
538
|
-
renderSessionView: renderSessionView,
|
539
|
-
resizeView: resizeView,
|
540
|
-
init: init
|
541
|
-
};
|
542
|
-
|
543
|
-
})();
|