fnordmetric 0.5.9 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +19 -0
- data/VERSION +1 -1
- data/doc/ulm_stats.rb +18 -0
- data/fnordmetric.gemspec +2 -2
- data/lib/fnordmetric.rb +6 -1
- data/lib/fnordmetric/app.rb +2 -0
- data/lib/fnordmetric/event.rb +68 -60
- data/lib/fnordmetric/inbound_stream.rb +2 -1
- data/lib/fnordmetric/namespace.rb +1 -0
- data/lib/fnordmetric/session.rb +3 -2
- data/pub/fnordmetric.css +5 -2
- data/pub/fnordmetric.js +69 -14
- data/spec/app_spec.rb +33 -1
- data/spec/event_spec.rb +44 -1
- data/spec/session_spec.rb +3 -3
- metadata +38 -38
data/README.md
CHANGED
@@ -277,6 +277,23 @@ FnordMetric.namespace :myapp do
|
|
277
277
|
|
278
278
|
end
|
279
279
|
|
280
|
+
FnordMetric.server_configuration = {
|
281
|
+
:redis_url => "redis://localhost:6379",
|
282
|
+
:redis_prefix => "fnordmetric",
|
283
|
+
:inbound_stream => ["0.0.0.0", "1339"],
|
284
|
+
:start_worker => true,
|
285
|
+
:print_stats => 3,
|
286
|
+
|
287
|
+
# events that aren't processed after 2 min get dropped
|
288
|
+
:event_queue_ttl => 120,
|
289
|
+
|
290
|
+
# event data is kept for one month
|
291
|
+
:event_data_ttl => 3600*24*30,
|
292
|
+
|
293
|
+
# session data is kept for one month
|
294
|
+
:session_data_ttl => 3600*24*30
|
295
|
+
}
|
296
|
+
|
280
297
|
FnordMetric.standalone
|
281
298
|
```
|
282
299
|
|
@@ -288,6 +305,8 @@ Contributors
|
|
288
305
|
+ Marco Borromeo (http://github.com/mborromeo)
|
289
306
|
+ Leo Lou (http://github.com/l4u)
|
290
307
|
+ Andy Lindeman (http://github.com/alindeman)
|
308
|
+
+ Jurriaan Pruis (http://github.com/jurriaan)
|
309
|
+
+ Kacper Bielecki (http://github.com/kazjote)
|
291
310
|
|
292
311
|
To contribute, please fork this repository, make your changes and run the specs, commit them to your github repository and send me a pull request.
|
293
312
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/doc/ulm_stats.rb
CHANGED
@@ -615,6 +615,24 @@ FnordMetric.namespace :ulm do
|
|
615
615
|
|
616
616
|
end
|
617
617
|
|
618
|
+
FnordMetric.server_configuration = {
|
619
|
+
:redis_url => "redis://localhost:6379",
|
620
|
+
:redis_prefix => "fnordmetric",
|
621
|
+
:inbound_stream => ["0.0.0.0", "1337"],
|
622
|
+
:web_interface => ["0.0.0.0", "4242"],
|
623
|
+
:start_worker => true,
|
624
|
+
:print_stats => 3,
|
625
|
+
|
626
|
+
# events that aren't processed after 2 min get dropped
|
627
|
+
:event_queue_ttl => 120,
|
628
|
+
|
629
|
+
# event data is kept for one month
|
630
|
+
:event_data_ttl => 3600*24*30,
|
631
|
+
|
632
|
+
# session data is kept for one month
|
633
|
+
:session_data_ttl => 3600*24*30
|
634
|
+
}
|
635
|
+
|
618
636
|
#task :setup do
|
619
637
|
# @fm_opts = {:web_interface => ["0.0.0.0", "2323"]} if ENV['DEV']
|
620
638
|
#end
|
data/fnordmetric.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "fnordmetric"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.6.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Paul Asmuth"]
|
12
|
-
s.date = "2012-01-
|
12
|
+
s.date = "2012-01-11"
|
13
13
|
s.description = "FnordMetric is a Ruby Event-Tracking gem on steroids"
|
14
14
|
s.email = "paul@paulasmuth.com"
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/fnordmetric.rb
CHANGED
@@ -15,6 +15,10 @@ module FnordMetric
|
|
15
15
|
def self.namespace(key=nil, &block)
|
16
16
|
@@namespaces[key] = block
|
17
17
|
end
|
18
|
+
|
19
|
+
def self.server_configuration=(configuration)
|
20
|
+
@@server_configuration = configuration
|
21
|
+
end
|
18
22
|
|
19
23
|
def self.default_options(opts)
|
20
24
|
|
@@ -90,7 +94,8 @@ module FnordMetric
|
|
90
94
|
puts(msg); exit!
|
91
95
|
end
|
92
96
|
|
93
|
-
def self.run
|
97
|
+
def self.run
|
98
|
+
opts = (defined?(@@server_configuration) && @@server_configuration) || {}
|
94
99
|
start_em(opts)
|
95
100
|
rescue Exception => e
|
96
101
|
log "!!! eventmachine died, restarting... #{e.message}"
|
data/lib/fnordmetric/app.rb
CHANGED
@@ -97,6 +97,8 @@ class FnordMetric::App < Sinatra::Base
|
|
97
97
|
|
98
98
|
events = if params[:type]
|
99
99
|
current_namespace.events(:by_type, :type => params[:type])
|
100
|
+
elsif params[:session_key]
|
101
|
+
current_namespace.events(:by_session_key, :session_key => params[:session_key])
|
100
102
|
else
|
101
103
|
find_opts = { :limit => 100 }
|
102
104
|
find_opts.merge!(:since => params[:since].to_i+1) if params[:since]
|
data/lib/fnordmetric/event.rb
CHANGED
@@ -1,78 +1,86 @@
|
|
1
|
-
|
1
|
+
module FnordMetric
|
2
|
+
class Event
|
2
3
|
|
3
|
-
|
4
|
+
attr_accessor :time, :type, :event_id
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
#def self.track!(event_type, event_data)
|
7
|
+
#end
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
def self.all(opts)
|
10
|
+
range_opts = { :withscores => true }
|
11
|
+
range_opts.merge!(:limit => [0,opts[:limit]]) if opts[:limit]
|
12
|
+
opts[:redis].zrevrangebyscore(
|
13
|
+
"#{opts[:namespace_prefix]}-timeline",
|
14
|
+
'+inf', opts[:since]||'0',
|
15
|
+
range_opts
|
16
|
+
).in_groups_of(2).map do |event_id, ts|
|
17
|
+
next if event_id.blank?
|
18
|
+
find(event_id, opts).tap{ |e| e.time = ts }
|
19
|
+
end
|
18
20
|
end
|
19
|
-
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
22
|
+
def self.by_type(_type, opts)
|
23
|
+
opts[:redis].lrange(
|
24
|
+
"#{opts[:namespace_prefix]}-type-#{_type}",
|
25
|
+
0, 200).map do |event_id|
|
26
|
+
next if event_id.blank?
|
27
|
+
find(event_id, opts).tap{ |e| }
|
28
|
+
end
|
27
29
|
end
|
28
|
-
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
def self.by_session_key(_session_key, opts)
|
32
|
+
session = Session.find(_session_key, opts)
|
33
|
+
session.fetch_event_ids!(200).reject(&:blank?).map do |event_id|
|
34
|
+
find(event_id, opts)
|
35
|
+
end
|
33
36
|
end
|
34
|
-
end
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
def self.find(event_id, opts)
|
39
|
+
self.new(event_id, opts).tap do |event|
|
40
|
+
event.fetch!
|
41
|
+
end
|
42
|
+
end
|
40
43
|
|
41
|
-
|
42
|
-
|
43
|
-
@
|
44
|
+
def initialize(event_id, opts)
|
45
|
+
@opts = opts
|
46
|
+
@event_id = event_id
|
44
47
|
end
|
45
|
-
end
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
def fetch!
|
50
|
+
@data = JSON.parse(fetch_json).tap do |event|
|
51
|
+
@type = event.delete("_type")
|
52
|
+
end
|
53
|
+
end
|
50
54
|
|
51
|
-
|
52
|
-
|
53
|
-
|
55
|
+
def fetch_json
|
56
|
+
@opts[:redis].get(redis_key) || "{}"
|
57
|
+
end
|
54
58
|
|
55
|
-
|
56
|
-
|
57
|
-
|
59
|
+
def redis_key
|
60
|
+
[@opts[:redis_prefix], :event, @event_id].join("-")
|
61
|
+
end
|
58
62
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
def data(key=nil)
|
64
|
-
key ? @data[key.to_s] : @data
|
65
|
-
end
|
63
|
+
def session_key
|
64
|
+
@data["_session"] ? Digest::MD5.hexdigest(@data["_session"]) : nil
|
65
|
+
end
|
66
66
|
|
67
|
-
|
67
|
+
def id
|
68
|
+
@event_id
|
69
|
+
end
|
70
|
+
|
71
|
+
def data(key=nil)
|
72
|
+
key ? @data[key.to_s] : @data
|
73
|
+
end
|
68
74
|
|
69
|
-
|
70
|
-
@data.merge!(
|
71
|
-
:_type => @type,
|
72
|
-
:_session_key => session_key,
|
73
|
-
:_eid => @event_id,
|
74
|
-
:_time => @time
|
75
|
-
)
|
76
|
-
end
|
75
|
+
alias :[] :data
|
77
76
|
|
78
|
-
|
77
|
+
def to_json
|
78
|
+
@data.merge!(
|
79
|
+
:_type => @type,
|
80
|
+
:_session_key => session_key,
|
81
|
+
:_eid => @event_id,
|
82
|
+
:_time => @time
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'securerandom'
|
1
2
|
class FnordMetric::InboundStream < EventMachine::Connection
|
2
3
|
|
3
4
|
@@opts = nil
|
@@ -43,7 +44,7 @@ class FnordMetric::InboundStream < EventMachine::Connection
|
|
43
44
|
end
|
44
45
|
|
45
46
|
def get_next_uuid
|
46
|
-
|
47
|
+
SecureRandom.uuid
|
47
48
|
end
|
48
49
|
|
49
50
|
def close_connection?
|
@@ -77,6 +77,7 @@ class FnordMetric::Namespace
|
|
77
77
|
def events(_ids, opts={})
|
78
78
|
return FnordMetric::Event.all(extend_opts(opts)) if _ids == :all
|
79
79
|
return FnordMetric::Event.by_type(opts.delete(:type), extend_opts(opts)) if _ids == :by_type
|
80
|
+
return FnordMetric::Event.by_session_key(opts.delete(:session_key), extend_opts(opts)) if _ids == :by_session_key
|
80
81
|
end
|
81
82
|
|
82
83
|
def method_missing(m, *args, &block)
|
data/lib/fnordmetric/session.rb
CHANGED
@@ -89,6 +89,7 @@ class FnordMetric::Session
|
|
89
89
|
|
90
90
|
def add_event(event)
|
91
91
|
@redis.zadd(redis_key(:events), event[:_time], event[:_eid])
|
92
|
+
|
92
93
|
add_data(:_picture, event[:url]) if event[:_type] == "_set_picture"
|
93
94
|
add_data(:_name, event[:name]) if event[:_type] == "_set_name"
|
94
95
|
add_event_data(event) if event[:_type] == "_set_data"
|
@@ -125,7 +126,7 @@ class FnordMetric::Session
|
|
125
126
|
|
126
127
|
def fetch_event_ids!(since=-1)
|
127
128
|
# FIXME: use WITHSCORE to get the timestamps and return event objects
|
128
|
-
@event_ids = @redis.
|
129
|
+
@event_ids = @redis.zrevrange(redis_key(:events), 0, since)
|
129
130
|
end
|
130
131
|
|
131
|
-
end
|
132
|
+
end
|
data/pub/fnordmetric.css
CHANGED
@@ -107,11 +107,14 @@ text-shadow: 1px 0px 2px rgba(255, 255, 255, 1);
|
|
107
107
|
|
108
108
|
|
109
109
|
ul.session_list{ list-style-type:none; margin:0; padding:9px 16px 0 11px; }
|
110
|
-
ul.session_list li{ color:#0A0A0A;
|
110
|
+
ul.session_list li{ color:#0A0A0A; height:32px; overflow:hidden; line-height:18px; padding:4px; }
|
111
111
|
ul.session_list li:hover{ background:#eee; cursor:pointer; }
|
112
|
+
ul.session_list li input{ float: left; margin-right: 7px; }
|
112
113
|
ul.session_list li .picture{ height:18px; width:18px; float:left; background:#333; overflow:hidden; }
|
113
114
|
ul.session_list li .name{ float:left; width:120px; overflow:hidden; margin-left:10px; font-size:12px; }
|
114
115
|
ul.session_list li .time{ float:right; width:40px; overflow:hidden; text-align:right; font-size:10px; }
|
116
|
+
ul.session_list li .history{ float:right; color:#999; font-size:10px; line-height: 12px;}
|
117
|
+
ul.session_list li .history:hover{ color:#333; text-decoration:underline; }
|
115
118
|
|
116
119
|
.sessions_feed{ min-width:300px; min-height:100px; float:left; }
|
117
120
|
.sessions_feed ul.feed_inner{ margin:5px 15px; min-height:100px; padding:0px; }
|
@@ -139,4 +142,4 @@ ul.event_type_list li .history:hover{ color:#333; text-decoration:underline; }
|
|
139
142
|
height: 0;
|
140
143
|
}
|
141
144
|
|
142
|
-
.highcharts-series circle{ stroke-width:1px; }
|
145
|
+
.highcharts-series circle{ stroke-width:1px; }
|
data/pub/fnordmetric.js
CHANGED
@@ -78,9 +78,15 @@ var FnordMetric = (function(){
|
|
78
78
|
}
|
79
79
|
}
|
80
80
|
|
81
|
+
function formatPercentValue(value){
|
82
|
+
return value + '%';
|
83
|
+
}
|
84
|
+
|
81
85
|
function formatGaugeValue(gauge_key, value){
|
82
86
|
if(gauge_key.slice(0,8) === '__time__'){
|
83
87
|
return formatTimeValue(value);
|
88
|
+
} else if(gauge_key.slice(0,11) === '__percent__'){
|
89
|
+
return formatPercentValue(value);
|
84
90
|
} else {
|
85
91
|
return formatValue(value);
|
86
92
|
}
|
@@ -733,7 +739,7 @@ var FnordMetric = (function(){
|
|
733
739
|
).append(listElem);
|
734
740
|
|
735
741
|
var eventsPolledUntil = false;
|
736
|
-
var eventsFilter = [];
|
742
|
+
var eventsFilter = {uncheckedTypes: [], checkedSessions: []};
|
737
743
|
var sessionData = {};
|
738
744
|
var pollRunning = true;
|
739
745
|
|
@@ -771,10 +777,11 @@ var FnordMetric = (function(){
|
|
771
777
|
});
|
772
778
|
};
|
773
779
|
|
774
|
-
function loadEventHistory(
|
780
|
+
function loadEventHistory(params){
|
775
781
|
feedInnerElem.html('');
|
776
782
|
$.ajax({
|
777
|
-
url: FnordMetric.p + '/' + currentNamespace+'/events
|
783
|
+
url: FnordMetric.p + '/' + currentNamespace+'/events',
|
784
|
+
data: params,
|
778
785
|
success: function(_data, _status){
|
779
786
|
var data = JSON.parse(_data).events;
|
780
787
|
for(var n=data.length; n >= 0; n--){
|
@@ -807,14 +814,19 @@ var FnordMetric = (function(){
|
|
807
814
|
});
|
808
815
|
};
|
809
816
|
|
817
|
+
function setCheckboxesCheckedState(types_state, sessions_state) {
|
818
|
+
$('.event_type_list .event_type input').attr('checked', types_state);
|
819
|
+
$('.session_list .session input').attr('checked', sessions_state);
|
820
|
+
}
|
821
|
+
|
810
822
|
function addEventType(type, display){
|
811
823
|
typeListElem.append(
|
812
824
|
$('<li class="event_type"></li>').append(
|
813
825
|
$('<span class="history"></span>').html('history')
|
814
826
|
.click(function(){
|
815
|
-
|
827
|
+
setCheckboxesCheckedState(true, true);
|
816
828
|
$('input', $(this).parent()).attr('checked', true);
|
817
|
-
updateEventFilter(); loadEventHistory(type);
|
829
|
+
updateEventFilter(); loadEventHistory({type: type});
|
818
830
|
})
|
819
831
|
).append(
|
820
832
|
$('<input type="checkbox" />').attr('checked', true)
|
@@ -832,7 +844,15 @@ var FnordMetric = (function(){
|
|
832
844
|
_unchecked_types.push($(v).attr('rel'));
|
833
845
|
}
|
834
846
|
});
|
835
|
-
eventsFilter = _unchecked_types;
|
847
|
+
eventsFilter.uncheckedTypes = _unchecked_types;
|
848
|
+
|
849
|
+
var _checked_sessions = [];
|
850
|
+
$('ul.session_list li.session').each(function(i,v){
|
851
|
+
if($('input', v).attr('checked')){
|
852
|
+
_checked_sessions.push($(v).data().session);
|
853
|
+
}
|
854
|
+
});
|
855
|
+
eventsFilter.checkedSessions = _checked_sessions;
|
836
856
|
}
|
837
857
|
|
838
858
|
function doEventsPoll(){
|
@@ -848,18 +868,40 @@ var FnordMetric = (function(){
|
|
848
868
|
return (function(_data, _status){
|
849
869
|
var data = JSON.parse(_data)
|
850
870
|
var events = data.events;
|
851
|
-
var
|
871
|
+
var timeout = 1000;
|
852
872
|
var maxevents = 200;
|
873
|
+
var passesFiltering = function(event_data) {
|
874
|
+
var passes_type_filtering = false;
|
875
|
+
var passes_session_filtering = false;
|
876
|
+
if(eventsFilter.uncheckedTypes.indexOf(event_data._type) == -1) {
|
877
|
+
if(parseInt(v._time)<=eventsPolledUntil) {
|
878
|
+
passes_type_filtering = true;
|
879
|
+
}
|
880
|
+
}
|
881
|
+
if(!passes_type_filtering) return false;
|
882
|
+
|
883
|
+
if(eventsFilter.checkedSessions.length == 0){
|
884
|
+
return true; // No filter set - show all events
|
885
|
+
} else {
|
886
|
+
if(event_data._session_key){
|
887
|
+
if(eventsFilter.checkedSessions.indexOf(event_data._session_key) >= 0){
|
888
|
+
return true; // Filter set and match
|
889
|
+
} else {
|
890
|
+
return false; // Filter set but no match
|
891
|
+
}
|
892
|
+
} else {
|
893
|
+
return false; // Filter set but event is not associated with session
|
894
|
+
}
|
895
|
+
}
|
896
|
+
}
|
897
|
+
|
853
898
|
if(events.length > 0){
|
854
|
-
timeout = 200;
|
855
899
|
eventsPolledUntil = parseInt(events[0]._time)-1;
|
856
900
|
}
|
857
901
|
for(var n=events.length-1; n >= 0; n--){
|
858
902
|
var v = events[n];
|
859
|
-
if(
|
860
|
-
|
861
|
-
renderEvent(v);
|
862
|
-
}
|
903
|
+
if(passesFiltering(v)) {
|
904
|
+
renderEvent(v);
|
863
905
|
}
|
864
906
|
};
|
865
907
|
var elems = $("p", feedInnerElem);
|
@@ -867,13 +909,17 @@ var FnordMetric = (function(){
|
|
867
909
|
$(elems[n]).remove();
|
868
910
|
}
|
869
911
|
if(pollRunning){
|
870
|
-
window.setTimeout(doEventsPoll(),
|
912
|
+
window.setTimeout(doEventsPoll(), timeout);
|
871
913
|
}
|
872
914
|
});
|
873
915
|
};
|
874
916
|
|
875
917
|
function updateSession(session_data){
|
876
|
-
|
918
|
+
var session_key = session_data.session_key;
|
919
|
+
if(!sessionData[session_key]){
|
920
|
+
updateEventFilter()
|
921
|
+
}
|
922
|
+
sessionData[session_key] = session_data;
|
877
923
|
renderSession(session_data);
|
878
924
|
}
|
879
925
|
|
@@ -913,11 +959,20 @@ var FnordMetric = (function(){
|
|
913
959
|
|
914
960
|
listElem.append(
|
915
961
|
$('<li class="session"></li>').append(
|
962
|
+
$('<input type="checkbox" />').click(function(){ updateEventFilter(); })
|
963
|
+
).append(
|
916
964
|
$('<div class="picture"></div>').html(session_picture)
|
917
965
|
).append(
|
918
966
|
$('<span class="name"></span>').html(session_name)
|
919
967
|
).append(
|
920
968
|
$('<span class="time"></span>').html(session_time)
|
969
|
+
).append(
|
970
|
+
$('<span class="history"></span>').html('history')
|
971
|
+
.click(function(){
|
972
|
+
setCheckboxesCheckedState(true, false);
|
973
|
+
$('input', $(this).parent()).attr('checked', true);
|
974
|
+
updateEventFilter(); loadEventHistory({session_key: session_data["session_key"]});
|
975
|
+
})
|
921
976
|
).attr('data-session', session_data["session_key"])
|
922
977
|
);
|
923
978
|
|
data/spec/app_spec.rb
CHANGED
@@ -334,6 +334,38 @@ describe "app" do
|
|
334
334
|
JSON.parse(last_response.body)["events"].length.should == 1
|
335
335
|
end
|
336
336
|
|
337
|
+
it "should render all events for a single session key" do
|
338
|
+
@namespace.ready!(@redis_wrap).announce(
|
339
|
+
:_time => @now,
|
340
|
+
:_session => "max_session",
|
341
|
+
:_eid => "124234"
|
342
|
+
)
|
343
|
+
@namespace.ready!(@redis_wrap).announce(
|
344
|
+
:_time => @now,
|
345
|
+
:_session => "kate_session",
|
346
|
+
:_eid => "12235234"
|
347
|
+
)
|
348
|
+
@namespace.ready!(@redis_wrap).announce(
|
349
|
+
:_time => @now,
|
350
|
+
:_session => "kate_session",
|
351
|
+
:_eid => "124234234"
|
352
|
+
)
|
353
|
+
@namespace.ready!(@redis_wrap).announce(
|
354
|
+
:_time => @now,
|
355
|
+
:_eid => "124234234"
|
356
|
+
)
|
357
|
+
max_session_key = Digest::MD5.hexdigest "max_session"
|
358
|
+
kate_session_key = Digest::MD5.hexdigest "kate_session"
|
359
|
+
|
360
|
+
get "/foospace/events?session_key=#{max_session_key}"
|
361
|
+
events = JSON.parse(last_response.body)["events"]
|
362
|
+
events.length.should == 1
|
363
|
+
|
364
|
+
get "/foospace/events?session_key=#{kate_session_key}"
|
365
|
+
events = JSON.parse(last_response.body)["events"]
|
366
|
+
events.length.should == 2
|
367
|
+
end
|
368
|
+
|
337
369
|
it "should render a list of event types" do
|
338
370
|
@namespace.ready!(@redis_wrap).announce(
|
339
371
|
:_type => "fn0rd",
|
@@ -449,4 +481,4 @@ describe "app" do
|
|
449
481
|
|
450
482
|
end
|
451
483
|
|
452
|
-
end
|
484
|
+
end
|
data/spec/event_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require ::File.expand_path('../spec_helper.rb', __FILE__)
|
2
|
+
require 'irb'
|
2
3
|
|
3
4
|
describe FnordMetric::Event do
|
4
5
|
|
@@ -116,6 +117,48 @@ describe FnordMetric::Event do
|
|
116
117
|
Event.by_type('f00bar', @opts).length.should == 1
|
117
118
|
end
|
118
119
|
|
120
|
+
describe "looking by session_key" do
|
121
|
+
let(:namespace) do
|
122
|
+
options = {:redis_prefix => "fnordmetric-test", :session_data_ttl => 1}
|
123
|
+
Namespace.new(:ns123, options)
|
124
|
+
end
|
125
|
+
|
126
|
+
let(:events_data) do
|
127
|
+
[[1, "max_session"], [2, "kate_session"], [3, "kate_session"], [12345678, nil]]
|
128
|
+
end
|
129
|
+
|
130
|
+
let(:kate_session_key) { Digest::MD5.hexdigest "kate_session" }
|
131
|
+
let(:events) { Event.by_session_key kate_session_key, @opts }
|
132
|
+
|
133
|
+
before do
|
134
|
+
created_events_data.each do |(event_id, session)|
|
135
|
+
event_data = { :_time => @now + event_id, :_eid => event_id }
|
136
|
+
event_data[:_session] = session if session
|
137
|
+
namespace.ready!(@redis_wrap).announce event_data
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "when events are added in ascending time order" do
|
142
|
+
let(:created_events_data) { events_data }
|
143
|
+
|
144
|
+
it "should find correct events" do
|
145
|
+
["2","3"].each {|id| events.map(&:id).should include(id) }
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should have correct order" do
|
149
|
+
events.map(&:id).should == ["3","2"]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "when events are added in descending time order" do
|
154
|
+
let(:created_events_data) { events_data.reverse }
|
155
|
+
|
156
|
+
it "should have correct order" do
|
157
|
+
events.map(&:id).should == ["3","2"]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
119
162
|
def create_event(event_id, event_data)
|
120
163
|
@redis_wrap.zadd(@timeline, event_data.delete(:_time), event_id)
|
121
164
|
@redis.set("fnordmetric-test-event-#{event_id}", event_data.to_json)
|
@@ -124,4 +167,4 @@ describe FnordMetric::Event do
|
|
124
167
|
end
|
125
168
|
|
126
169
|
|
127
|
-
end
|
170
|
+
end
|
data/spec/session_spec.rb
CHANGED
@@ -212,8 +212,8 @@ describe FnordMetric::Session do
|
|
212
212
|
@redis_wrap.zadd("#{@namespace}-session-#{sesshash}-events", @now, "fnord")
|
213
213
|
sess = Session.find(sesshash, @opts)
|
214
214
|
sess.fetch_event_ids!
|
215
|
-
sess.event_ids
|
216
|
-
sess.event_ids
|
215
|
+
sess.event_ids.should include("shmoo")
|
216
|
+
sess.event_ids.should include("fnord")
|
217
217
|
end
|
218
218
|
|
219
219
|
def create_session(sesskey, sesstime, sessdata)
|
@@ -228,4 +228,4 @@ describe FnordMetric::Session do
|
|
228
228
|
end
|
229
229
|
|
230
230
|
|
231
|
-
end
|
231
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fnordmetric
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bson_ext
|
16
|
-
requirement: &
|
16
|
+
requirement: &70186955498840 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 1.4.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70186955498840
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: sinatra
|
27
|
-
requirement: &
|
27
|
+
requirement: &70186955498360 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 1.2.6
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70186955498360
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: redis
|
38
|
-
requirement: &
|
38
|
+
requirement: &70186955497820 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: 2.2.2
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70186955497820
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: eventmachine
|
49
|
-
requirement: &
|
49
|
+
requirement: &70186955497320 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70186955497320
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: em-hiredis
|
60
|
-
requirement: &
|
60
|
+
requirement: &70186955496720 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70186955496720
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: json
|
71
|
-
requirement: &
|
71
|
+
requirement: &70186955496080 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70186955496080
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: i18n
|
82
|
-
requirement: &
|
82
|
+
requirement: &70186955495200 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70186955495200
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: haml
|
93
|
-
requirement: &
|
93
|
+
requirement: &70186955494700 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :runtime
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70186955494700
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: rack
|
104
|
-
requirement: &
|
104
|
+
requirement: &70186955494200 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70186955494200
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: rack-test
|
115
|
-
requirement: &
|
115
|
+
requirement: &70186955490620 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: '0'
|
121
121
|
type: :runtime
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70186955490620
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: yajl-ruby
|
126
|
-
requirement: &
|
126
|
+
requirement: &70186955490140 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :runtime
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *70186955490140
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: thin
|
137
|
-
requirement: &
|
137
|
+
requirement: &70186955489620 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ! '>='
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: '0'
|
143
143
|
type: :runtime
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *70186955489620
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: activesupport
|
148
|
-
requirement: &
|
148
|
+
requirement: &70186955489120 !ruby/object:Gem::Requirement
|
149
149
|
none: false
|
150
150
|
requirements:
|
151
151
|
- - ! '>='
|
@@ -153,10 +153,10 @@ dependencies:
|
|
153
153
|
version: '0'
|
154
154
|
type: :runtime
|
155
155
|
prerelease: false
|
156
|
-
version_requirements: *
|
156
|
+
version_requirements: *70186955489120
|
157
157
|
- !ruby/object:Gem::Dependency
|
158
158
|
name: delorean
|
159
|
-
requirement: &
|
159
|
+
requirement: &70186955488640 !ruby/object:Gem::Requirement
|
160
160
|
none: false
|
161
161
|
requirements:
|
162
162
|
- - ! '>='
|
@@ -164,10 +164,10 @@ dependencies:
|
|
164
164
|
version: '0'
|
165
165
|
type: :development
|
166
166
|
prerelease: false
|
167
|
-
version_requirements: *
|
167
|
+
version_requirements: *70186955488640
|
168
168
|
- !ruby/object:Gem::Dependency
|
169
169
|
name: rspec
|
170
|
-
requirement: &
|
170
|
+
requirement: &70186955488160 !ruby/object:Gem::Requirement
|
171
171
|
none: false
|
172
172
|
requirements:
|
173
173
|
- - ~>
|
@@ -175,10 +175,10 @@ dependencies:
|
|
175
175
|
version: 2.6.0
|
176
176
|
type: :development
|
177
177
|
prerelease: false
|
178
|
-
version_requirements: *
|
178
|
+
version_requirements: *70186955488160
|
179
179
|
- !ruby/object:Gem::Dependency
|
180
180
|
name: shoulda
|
181
|
-
requirement: &
|
181
|
+
requirement: &70186955487680 !ruby/object:Gem::Requirement
|
182
182
|
none: false
|
183
183
|
requirements:
|
184
184
|
- - ! '>='
|
@@ -186,10 +186,10 @@ dependencies:
|
|
186
186
|
version: '0'
|
187
187
|
type: :development
|
188
188
|
prerelease: false
|
189
|
-
version_requirements: *
|
189
|
+
version_requirements: *70186955487680
|
190
190
|
- !ruby/object:Gem::Dependency
|
191
191
|
name: bundler
|
192
|
-
requirement: &
|
192
|
+
requirement: &70186955487140 !ruby/object:Gem::Requirement
|
193
193
|
none: false
|
194
194
|
requirements:
|
195
195
|
- - ~>
|
@@ -197,10 +197,10 @@ dependencies:
|
|
197
197
|
version: 1.0.0
|
198
198
|
type: :development
|
199
199
|
prerelease: false
|
200
|
-
version_requirements: *
|
200
|
+
version_requirements: *70186955487140
|
201
201
|
- !ruby/object:Gem::Dependency
|
202
202
|
name: jeweler
|
203
|
-
requirement: &
|
203
|
+
requirement: &70186955486600 !ruby/object:Gem::Requirement
|
204
204
|
none: false
|
205
205
|
requirements:
|
206
206
|
- - ~>
|
@@ -208,7 +208,7 @@ dependencies:
|
|
208
208
|
version: 1.5.2
|
209
209
|
type: :development
|
210
210
|
prerelease: false
|
211
|
-
version_requirements: *
|
211
|
+
version_requirements: *70186955486600
|
212
212
|
description: FnordMetric is a Ruby Event-Tracking gem on steroids
|
213
213
|
email: paul@paulasmuth.com
|
214
214
|
executables: []
|