panmind-usage-tracker 0.4.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +15 -0
- data/README.md +28 -25
- data/Rakefile +8 -6
- data/VERSION +1 -1
- data/bin/usage_tracker +1 -1
- data/config/usage_tracker.yml.sample +19 -2
- data/lib/usage_tracker.rb +26 -41
- data/lib/usage_tracker/adapter.rb +19 -0
- data/lib/usage_tracker/adapters/couchdb.rb +35 -0
- data/lib/usage_tracker/adapters/mongodb.rb +23 -0
- data/lib/usage_tracker/log.rb +15 -0
- data/lib/usage_tracker/middleware.rb +35 -21
- data/lib/usage_tracker/reactor.rb +3 -71
- data/lib/usage_tracker/runner.rb +54 -0
- data/panmind-usage-tracker.gemspec +48 -10
- data/spec/spec_helper.rb +6 -0
- data/spec/usage_tracker_spec.rb +39 -0
- metadata +143 -31
- data/config/views.yml +0 -139
- data/middleware_test.rb +0 -190
data/config/views.yml
DELETED
@@ -1,139 +0,0 @@
|
|
1
|
-
<%
|
2
|
-
# Currently defined path prefixes, in JS Regexp format
|
3
|
-
#
|
4
|
-
_AREAS_RE = '\/(' << %w( inbox res projects users account publish search ).join('|') << ')'
|
5
|
-
|
6
|
-
# Expands to JS code that defines the "area" variable by
|
7
|
-
# executing the _AREAS_RE regexp onto the "path_info"
|
8
|
-
# property of the "doc" object.
|
9
|
-
#
|
10
|
-
_GET_AREA = %(
|
11
|
-
var match = doc.env.path_info.match (/#{_AREAS_RE}/);
|
12
|
-
var area = match ? match[1] : 'other';
|
13
|
-
).gsub(/\s+/x, ' ').strip
|
14
|
-
%>
|
15
|
-
|
16
|
-
_id : '_design/basic'
|
17
|
-
language: 'javascript'
|
18
|
-
version : '2010110401' # Format: YYYY MM DD VV
|
19
|
-
views :
|
20
|
-
by_timestamp:
|
21
|
-
map: |
|
22
|
-
function (doc) {
|
23
|
-
if (doc.env)
|
24
|
-
emit (doc._id, doc);
|
25
|
-
}
|
26
|
-
|
27
|
-
by_date:
|
28
|
-
map: |
|
29
|
-
function (doc) {
|
30
|
-
var date = new Date (parseFloat (doc._id) * 1000);
|
31
|
-
emit([date.getUTCFullYear (), date.getUTCMonth (), date.getUTCDate ()], 1);
|
32
|
-
}
|
33
|
-
|
34
|
-
reduce: |
|
35
|
-
function (keys, values) {
|
36
|
-
return sum (values);
|
37
|
-
}
|
38
|
-
|
39
|
-
by_user_and_timestamp:
|
40
|
-
map: |
|
41
|
-
function (doc) {
|
42
|
-
if (doc.env)
|
43
|
-
emit ([doc.user_id, doc._id], doc);
|
44
|
-
}
|
45
|
-
|
46
|
-
res_count:
|
47
|
-
map: |
|
48
|
-
function (doc) {
|
49
|
-
if (doc.env && doc.env.path_info.indexOf ('res/') > 0)
|
50
|
-
emit (doc.env.path_info.split ('/')[2], 1);
|
51
|
-
}
|
52
|
-
reduce: |
|
53
|
-
function (keys, values, rereduce) {
|
54
|
-
return sum (values);
|
55
|
-
}
|
56
|
-
|
57
|
-
res_item_count:
|
58
|
-
map: |
|
59
|
-
function (doc) {
|
60
|
-
if (doc.env && doc.env.path_info.indexOf ('res/') > 0) {
|
61
|
-
var pieces = doc.env.path_info.split ('/');
|
62
|
-
if (pieces.length > 3)
|
63
|
-
emit ([pieces[2], pieces[3]], 1);
|
64
|
-
}
|
65
|
-
}
|
66
|
-
reduce: |
|
67
|
-
function (keys, values, rereduce) {
|
68
|
-
return sum (values);
|
69
|
-
}
|
70
|
-
|
71
|
-
user_res_count:
|
72
|
-
map: |
|
73
|
-
function (doc) {
|
74
|
-
if (doc.env && doc.env.path_info.indexOf ('res/') != -1)
|
75
|
-
emit ([doc.user_id, doc.env.path_info.split ('/')[2]], 1);
|
76
|
-
}
|
77
|
-
reduce: |
|
78
|
-
function (keys, values, rereduce) {
|
79
|
-
return sum (values);
|
80
|
-
}
|
81
|
-
|
82
|
-
user_area_count:
|
83
|
-
map: |
|
84
|
-
function (doc) {
|
85
|
-
if (doc.env) {
|
86
|
-
<%= _GET_AREA %>
|
87
|
-
emit ([doc.user_id, area], 1);
|
88
|
-
}
|
89
|
-
}
|
90
|
-
reduce: |
|
91
|
-
function (keys, values, rereduce) {
|
92
|
-
return sum (values);
|
93
|
-
}
|
94
|
-
|
95
|
-
area_count:
|
96
|
-
map: |
|
97
|
-
function (doc) {
|
98
|
-
if (doc.env) {
|
99
|
-
<%= _GET_AREA %>
|
100
|
-
emit (area, 1);
|
101
|
-
}
|
102
|
-
}
|
103
|
-
reduce: |
|
104
|
-
function (keys, values, rereduce) {
|
105
|
-
return sum (values);
|
106
|
-
}
|
107
|
-
|
108
|
-
average_duration_of_path:
|
109
|
-
map: |
|
110
|
-
function (doc) {
|
111
|
-
if (doc.duration)
|
112
|
-
emit (doc.env.path_info, doc.duration);
|
113
|
-
}
|
114
|
-
reduce: |
|
115
|
-
function (keys, values){
|
116
|
-
return Math.round (sum (values) / values.length);
|
117
|
-
}
|
118
|
-
|
119
|
-
average_duration_of_area:
|
120
|
-
map: |
|
121
|
-
function (doc) {
|
122
|
-
if (doc.duration) {
|
123
|
-
<%= _GET_AREA %>
|
124
|
-
emit (area, doc.duration)
|
125
|
-
}
|
126
|
-
}
|
127
|
-
reduce: |
|
128
|
-
function (keys, values){
|
129
|
-
return Math.round (sum (values) / values.length);
|
130
|
-
}
|
131
|
-
|
132
|
-
by_user_timestamp_area:
|
133
|
-
map: |
|
134
|
-
function (doc) {
|
135
|
-
if (doc.env) {
|
136
|
-
<%= _GET_AREA %>
|
137
|
-
emit ([doc.user_id, doc._id, area], doc);
|
138
|
-
}
|
139
|
-
}
|
data/middleware_test.rb
DELETED
@@ -1,190 +0,0 @@
|
|
1
|
-
################################################################
|
2
|
-
# ATTENTION
|
3
|
-
# make sure that a event-machine test reactor process is running
|
4
|
-
# ruby extras/usage_tracker/reactor.rb test
|
5
|
-
#
|
6
|
-
################################################################
|
7
|
-
|
8
|
-
# this checks the end-point of the usage tracking (arrival in the database) ->
|
9
|
-
# consider checking intermediate steps.......
|
10
|
-
require 'usage_tracker'
|
11
|
-
|
12
|
-
module UsageTracker
|
13
|
-
class IntegrationTest < ActionController::IntegrationTest
|
14
|
-
UsageTracker.connect!
|
15
|
-
|
16
|
-
context 'a request from a guest' do
|
17
|
-
should 'get tracked when successful' do
|
18
|
-
assert_difference 'doc_count' do
|
19
|
-
get '/'
|
20
|
-
assert_response :success
|
21
|
-
end
|
22
|
-
|
23
|
-
doc = last_tracking
|
24
|
-
assert_equal '/', doc.env.request_uri
|
25
|
-
assert_equal nil, doc.user_id
|
26
|
-
assert_equal 200, doc.status
|
27
|
-
assert doc.duration > 0
|
28
|
-
end
|
29
|
-
|
30
|
-
should 'get tracked when not found' do
|
31
|
-
get '/nonexistant'
|
32
|
-
assert_response :not_found
|
33
|
-
|
34
|
-
doc = last_tracking
|
35
|
-
assert_equal '/nonexistant', doc.env.request_uri
|
36
|
-
assert_equal 404, doc.status
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'a request from a logged-in user' do
|
41
|
-
setup do
|
42
|
-
@user = Factory.create(:confirmed_user)
|
43
|
-
post '/login', {:email => @user.email, :password => @user.password}, {'HTTPS' => 'on'}
|
44
|
-
assert_redirected_to plain_root_url
|
45
|
-
end
|
46
|
-
|
47
|
-
should 'get tracked when successful' do
|
48
|
-
assert_difference 'doc_count' do
|
49
|
-
get '/_'
|
50
|
-
assert_response :success
|
51
|
-
end
|
52
|
-
|
53
|
-
doc = last_tracking
|
54
|
-
|
55
|
-
assert_equal '/_', doc.env.request_uri
|
56
|
-
assert_equal @user.id, doc.user_id
|
57
|
-
assert_equal 200, doc.status
|
58
|
-
end
|
59
|
-
|
60
|
-
should 'get tracked when not found' do
|
61
|
-
get '/nonexistant'
|
62
|
-
assert_response :not_found
|
63
|
-
|
64
|
-
doc = last_tracking
|
65
|
-
|
66
|
-
assert_equal '/nonexistant', doc.env.request_uri
|
67
|
-
assert_equal @user.id, doc.user_id
|
68
|
-
assert_equal 404, doc.status
|
69
|
-
assert_equal false, doc.xhr
|
70
|
-
end
|
71
|
-
|
72
|
-
should 'get tracked when failed' do
|
73
|
-
xhr :get, '/projects/1/error', {}, {'HTTPS' => 'on'}
|
74
|
-
assert_response :internal_server_error
|
75
|
-
|
76
|
-
doc = last_tracking
|
77
|
-
|
78
|
-
assert_equal '/projects/1/error', doc.env.request_uri
|
79
|
-
assert_equal @user.id, doc.user_id
|
80
|
-
assert_equal 500, doc.status
|
81
|
-
assert_equal true, doc.xhr
|
82
|
-
assert_equal `hostname`.strip, doc.backend
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
fast_context "a search request" do
|
87
|
-
setup do
|
88
|
-
@res, @users, @assets =
|
89
|
-
mock_search_results_for(Array.new(2) { Factory.create(:res) }),
|
90
|
-
mock_search_results_for(Array.new(3) { Factory.create(:user) }),
|
91
|
-
mock_search_results_for(Network::AssetsController::ContentModels.map {|name|
|
92
|
-
Array.new(2) { Factory(name.underscore.to_sym).reload.asset } }.flatten)
|
93
|
-
|
94
|
-
Res.stubs(:search).returns(@res)
|
95
|
-
User.stubs(:search).returns(@users)
|
96
|
-
NetworkAsset.stubs(:search).returns(@assets)
|
97
|
-
end
|
98
|
-
|
99
|
-
should "be tracked with results" do
|
100
|
-
get '/search/e'
|
101
|
-
assert_response :success
|
102
|
-
|
103
|
-
doc = last_tracking
|
104
|
-
assert !doc.context.blank?
|
105
|
-
|
106
|
-
assert_equal 'e', doc.context.query
|
107
|
-
assert_equal [], doc.context.tags
|
108
|
-
assert_equal nil, doc.context.cat
|
109
|
-
|
110
|
-
assert_equal @res.map(&:id), doc.context.results.res
|
111
|
-
assert_equal @users.map(&:id), doc.context.results.users
|
112
|
-
assert_equal @assets.map(&:id), doc.context.results.assets
|
113
|
-
end
|
114
|
-
|
115
|
-
should "be tracked with tags" do
|
116
|
-
get '/search', :tag => 'a,b,c'
|
117
|
-
assert_response :success
|
118
|
-
|
119
|
-
doc = last_tracking
|
120
|
-
assert !doc.context.blank?
|
121
|
-
|
122
|
-
assert_equal '', doc.context.query
|
123
|
-
assert_equal %w(a b c), doc.context.tags
|
124
|
-
assert_equal nil, doc.context.cat
|
125
|
-
end
|
126
|
-
|
127
|
-
should "be tracked with tags and query" do
|
128
|
-
get '/search/antani', :tag => 'd,e,f'
|
129
|
-
assert_response :success
|
130
|
-
|
131
|
-
doc = last_tracking
|
132
|
-
assert !doc.context.blank?
|
133
|
-
|
134
|
-
assert_equal 'antani', doc.context.query
|
135
|
-
assert_equal %w(d e f), doc.context.tags
|
136
|
-
assert_equal nil, doc.context.cat
|
137
|
-
end
|
138
|
-
|
139
|
-
should "be tracked with category" do
|
140
|
-
cat = Factory.create(:res_category)
|
141
|
-
get '/search', :cat => cat.shortcut
|
142
|
-
assert_response :success
|
143
|
-
|
144
|
-
doc = last_tracking
|
145
|
-
assert !doc.context.blank?
|
146
|
-
|
147
|
-
assert_equal '', doc.context.query
|
148
|
-
assert_equal [], doc.context.tags
|
149
|
-
assert_equal cat.id, doc.context.cat
|
150
|
-
end
|
151
|
-
|
152
|
-
should "be tracked with category and query" do
|
153
|
-
cat = Factory.create(:res_category)
|
154
|
-
get '/search/res/asd', :cat => cat.shortcut
|
155
|
-
assert_response :success
|
156
|
-
|
157
|
-
doc = last_tracking
|
158
|
-
assert !doc.context.blank?
|
159
|
-
|
160
|
-
assert_equal 'asd', doc.context.query
|
161
|
-
assert_equal [], doc.context.tags
|
162
|
-
assert_equal cat.id, doc.context.cat
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
context "the middleware" do
|
167
|
-
should "not wait for more than a second before aborting" do
|
168
|
-
UDPSocket.expects(:open).once.yields(Class.new do
|
169
|
-
def write_nonblock(*args); sleep 0.7 end
|
170
|
-
def connect(*args) ; sleep 0.7 end
|
171
|
-
end.new)
|
172
|
-
|
173
|
-
assert_no_difference 'doc_count' do
|
174
|
-
get '/_'
|
175
|
-
assert_response :success
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
def last_tracking
|
181
|
-
sleep 0.3
|
182
|
-
UsageTracker.database.view('basic/by_timestamp', :descending => true, :limit => 1).rows.first.value
|
183
|
-
end
|
184
|
-
|
185
|
-
def doc_count
|
186
|
-
sleep 0.3
|
187
|
-
UsageTracker.database.info['doc_count']
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|