panmind-usage-tracker 0.4.0 → 1.0.1
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.
- 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
|