gricer 0.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/MIT-LICENSE +20 -0
- data/README.rdoc +84 -0
- data/Rakefile +49 -0
- data/app/assets/images/gricer/fluid/breadcrumb.png +0 -0
- data/app/assets/javascripts/gricer.js.coffee +85 -0
- data/app/assets/javascripts/gricer_backend_jquery.js.coffee +352 -0
- data/app/assets/javascripts/jquery.flot.js +2599 -0
- data/app/assets/javascripts/jquery.flot.pie.js +750 -0
- data/app/assets/javascripts/jquery.flot.resize.js +60 -0
- data/app/assets/javascripts/jquery.flot.symbol.js +70 -0
- data/app/assets/javascripts/worldmap.js +146 -0
- data/app/assets/stylesheets/gricer/fluid-jquery-ui.css.scss +1298 -0
- data/app/assets/stylesheets/gricer/fluid.css.scss +240 -0
- data/app/assets/stylesheets/gricer/helpers/css3.css.scss +21 -0
- data/app/controllers/gricer/base_controller.rb +141 -0
- data/app/controllers/gricer/capture_controller.rb +42 -0
- data/app/controllers/gricer/dashboard_controller.rb +18 -0
- data/app/controllers/gricer/requests_controller.rb +42 -0
- data/app/controllers/gricer/sessions_controller.rb +24 -0
- data/app/helpers/gricer/base_helper.rb +22 -0
- data/app/models/gricer/agent.rb +789 -0
- data/app/models/gricer/request.rb +239 -0
- data/app/models/gricer/session.rb +433 -0
- data/app/views/gricer/capture/index.html.erb +1 -0
- data/app/views/gricer/dashboard/_menu.html.erb +10 -0
- data/app/views/gricer/dashboard/_overview.html.erb +33 -0
- data/app/views/gricer/dashboard/index.html.erb +19 -0
- data/config/routes.rb +51 -0
- data/lib/gricer.rb +36 -0
- data/lib/gricer/action_controller/base.rb +28 -0
- data/lib/gricer/action_controller/track.rb +132 -0
- data/lib/gricer/active_model/statistics.rb +167 -0
- data/lib/gricer/config.rb +125 -0
- data/lib/gricer/engine.rb +9 -0
- data/lib/gricer/localization.rb +3 -0
- data/lib/tasks/gricer_tasks.rake +92 -0
- data/spec/controllers/gricer/base_controller_spec.rb +207 -0
- data/spec/controllers/gricer/capture_controller_spec.rb +44 -0
- data/spec/controllers/gricer/dashboard_controller_spec.rb +44 -0
- data/spec/controllers/gricer/requests_controller_spec.rb +36 -0
- data/spec/controllers/gricer/sessions_controller_spec.rb +37 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +9 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/assets/stylesheets/dashboard.css +4 -0
- data/spec/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/dummy/app/assets/stylesheets/sessions.css +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +23 -0
- data/spec/dummy/app/controllers/dashboard_controller.rb +19 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/helpers/dashboard_helper.rb +2 -0
- data/spec/dummy/app/views/dashboard/index.html.erb +236 -0
- data/spec/dummy/app/views/layouts/application.html.erb +16 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +48 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/cucumber.yml +9 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +27 -0
- data/spec/dummy/config/environments/production.rb +51 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +10 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +11 -0
- data/spec/dummy/db/schema.rb +241 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +26 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/helpers/gricer/base_helper_spec.rb +28 -0
- data/spec/lib/gricer/action_controller/track_spec.rb +63 -0
- data/spec/models/gricer/agent_spec.rb +829 -0
- data/spec/models/gricer/request_spec.rb +145 -0
- data/spec/models/gricer/session_spec.rb +209 -0
- data/spec/routing/capture_routes_spec.rb +6 -0
- data/spec/routing/dashboard_routes_spec.rb +9 -0
- data/spec/routing/requests_routes_spec.rb +90 -0
- data/spec/routing/sessions_routes_spec.rb +115 -0
- data/spec/spec_helper.rb +23 -0
- metadata +185 -0
@@ -0,0 +1,239 @@
|
|
1
|
+
module Gricer
|
2
|
+
# ActiveRecord Model for Request Statistics
|
3
|
+
# @attr [Gricer::Session] session
|
4
|
+
# The current value of the associated session.
|
5
|
+
#
|
6
|
+
# @attr [Gricer::Agent] agent
|
7
|
+
# The current value of the associated agent.
|
8
|
+
#
|
9
|
+
# @attr [String] host
|
10
|
+
# The current value of the host requested.
|
11
|
+
#
|
12
|
+
# @attr [String] path
|
13
|
+
# The current value of the path requested.
|
14
|
+
#
|
15
|
+
# @attr [String] method
|
16
|
+
# The current value of the method requested.
|
17
|
+
#
|
18
|
+
# @attr [String] protocol
|
19
|
+
# The current value of the protocol requested.
|
20
|
+
#
|
21
|
+
# @attr [String] controller
|
22
|
+
# The current value of the controller requested.
|
23
|
+
#
|
24
|
+
# @attr [String] action
|
25
|
+
# The current value of the action requested.
|
26
|
+
#
|
27
|
+
# @attr [String] format
|
28
|
+
# The current value of the format requested.
|
29
|
+
#
|
30
|
+
# @attr [String] param_id
|
31
|
+
# The current value of the http GET/POST id parameter requested.
|
32
|
+
#
|
33
|
+
# @attr [Integer] user_id
|
34
|
+
# The current id of the user logged in.
|
35
|
+
#
|
36
|
+
# @see Gricer::ActionController::Base#gricer_user_id
|
37
|
+
#
|
38
|
+
# @attr [Integer] status_code
|
39
|
+
# The current value of the HTTP status returned.
|
40
|
+
#
|
41
|
+
# @attr [String] content_type
|
42
|
+
# The current value of the content type returned.
|
43
|
+
#
|
44
|
+
# @attr [String] body_size
|
45
|
+
# The current size of the body returned.
|
46
|
+
#
|
47
|
+
# @attr [String] system_time
|
48
|
+
# The current value of the system time elapsed processing this request.
|
49
|
+
#
|
50
|
+
# @attr [String] user_time
|
51
|
+
# The current value of the user time elapsed processing this request.
|
52
|
+
#
|
53
|
+
# @attr [String] total_time
|
54
|
+
# The current value of the total time elapsed processing this request.
|
55
|
+
#
|
56
|
+
# @attr [String] real_time
|
57
|
+
# The current value of the real time elapsed processing this request.
|
58
|
+
#
|
59
|
+
# @attr [Boolean] javascript
|
60
|
+
# The current value of the javascript capability of the requesting agent.
|
61
|
+
#
|
62
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
63
|
+
#
|
64
|
+
# @attr [Integer] window_width
|
65
|
+
# The current value of the width in pixels of the requesting agent's window.
|
66
|
+
#
|
67
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
68
|
+
#
|
69
|
+
# @attr [Integer] window_height
|
70
|
+
# The current value of the height in pixels of the requesting agent's window.
|
71
|
+
#
|
72
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
73
|
+
#
|
74
|
+
# @attr [String] referer_protocol
|
75
|
+
# The current value of the protocol of the referering page.
|
76
|
+
#
|
77
|
+
# @attr [String] referer_host
|
78
|
+
# The current value of the host of the referering page.
|
79
|
+
#
|
80
|
+
# @attr [String] referer_path
|
81
|
+
# The current value of the path of the referering page.
|
82
|
+
#
|
83
|
+
# @attr [String] referer_params
|
84
|
+
# The current value of the params of the referering page.
|
85
|
+
#
|
86
|
+
# @attr [String] search_engine
|
87
|
+
# The current value of the search engine name refering to get to this request.
|
88
|
+
#
|
89
|
+
# @attr [String] search_query
|
90
|
+
# The current value of the search query refering to get to this request.
|
91
|
+
#
|
92
|
+
# @attr [Boolean] is_first_in_session
|
93
|
+
# The current value of the first in session flag.
|
94
|
+
# This is true if it is the first request within a Gricer::Session.
|
95
|
+
#
|
96
|
+
# @attr [String] locale_major
|
97
|
+
# The current value of the locale responded (major locale only)
|
98
|
+
#
|
99
|
+
# @attr [String] locale_minor
|
100
|
+
# The current value of the locale responded (major locale only)
|
101
|
+
#
|
102
|
+
# @attr [String] locale
|
103
|
+
# The current value of the locale responded
|
104
|
+
#
|
105
|
+
class Request < ::ActiveRecord::Base
|
106
|
+
set_table_name "#{::Gricer::config.table_name_prefix}requests"
|
107
|
+
include ActiveModel::Statistics
|
108
|
+
|
109
|
+
belongs_to :session, class_name: 'Gricer::Session', counter_cache: true
|
110
|
+
belongs_to :agent, class_name: 'Gricer::Agent', counter_cache: true
|
111
|
+
|
112
|
+
before_create :init_session
|
113
|
+
|
114
|
+
# Filter out anything that is not a Browser or MobileBrowser
|
115
|
+
# @return [ActiveRecord::Relation]
|
116
|
+
def self.browsers
|
117
|
+
includes("agent")
|
118
|
+
.where("\"#{Agent.table_name}\".\"agent_class_id\" IN (?)", [0x1000, 0x2000])
|
119
|
+
end
|
120
|
+
|
121
|
+
# Filter out anything that has not the first_in_session flag
|
122
|
+
# @return [ActiveRecord::Relation]
|
123
|
+
def self.only_first_in_session
|
124
|
+
where('is_first_in_session = ?', true)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Store the ip address from which the request was sent for init_session
|
128
|
+
# @see #init_session
|
129
|
+
def ip_address=(ip)
|
130
|
+
@ip_address = ip
|
131
|
+
end
|
132
|
+
|
133
|
+
# Find or Create Gricer::Agent corrosponding to the given user agent string as given in the HTTP header
|
134
|
+
#
|
135
|
+
# @param agent_header [String] A user agent string as in a HTTP header
|
136
|
+
# @return [Gricer::Agent]
|
137
|
+
def agent_header=(agent_header)
|
138
|
+
self.agent = Agent.find_or_create_by_request_header agent_header
|
139
|
+
end
|
140
|
+
|
141
|
+
# Parse the Ruby on Rails request to fill attributes
|
142
|
+
def request=(request)
|
143
|
+
self.ip_address = request.remote_ip
|
144
|
+
self.agent_header = request.headers['HTTP_USER_AGENT']
|
145
|
+
self.referer = request.headers['HTTP_X_FORWARDED_REFERER'] || request.headers['HTTP_REFERER']
|
146
|
+
|
147
|
+
self.host = request.host
|
148
|
+
self.path = request.path
|
149
|
+
self.method = request.request_method
|
150
|
+
self.protocol = request.protocol.sub(/[:\/]*$/, '').upcase
|
151
|
+
self.locale = I18n.locale
|
152
|
+
|
153
|
+
@request_locale = request.headers['HTTP_ACCEPT_LANGUAGE'].try(:split, ',').try(:first)
|
154
|
+
|
155
|
+
logger.debug I18n.locale
|
156
|
+
end
|
157
|
+
|
158
|
+
def locale=(locale)
|
159
|
+
self.locale_major, self.locale_minor = locale.try(:to_s).try(:downcase).try(:split, '-')
|
160
|
+
end
|
161
|
+
|
162
|
+
def locale
|
163
|
+
if locale_minor
|
164
|
+
"#{locale_major}-#{locale_minor}"
|
165
|
+
else
|
166
|
+
locale_major
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Parse the referer to fill referer and search engine attributes
|
171
|
+
#
|
172
|
+
# @param referer [String] The Referer as given in HTTP request
|
173
|
+
def referer=(referer)
|
174
|
+
if referer
|
175
|
+
void, self.referer_protocol, self.referer_host, self.referer_path, self.referer_params = referer.match(/([A-Za-z0-9]*):\/\/([^\/]*)([^\?]*)[\?]?(.*)/).to_a
|
176
|
+
|
177
|
+
# Sanatize/Normalize referer values
|
178
|
+
self.referer_protocol = referer_protocol.try(:upcase)
|
179
|
+
self.referer_host = referer_host.try(:downcase)
|
180
|
+
self.referer_path = '/' if referer_path.blank?
|
181
|
+
self.referer_params = nil if referer_params.blank?
|
182
|
+
params = CGI::parse(referer_params) unless referer_params.blank?
|
183
|
+
|
184
|
+
# Detect Search Engines
|
185
|
+
if referer_host =~ /^www\.google(?:\.com?)?(?:\.[a-z]{2})?$/ and ['/search', '/url'].include? referer_path
|
186
|
+
self.search_engine = 'Google'
|
187
|
+
self.search_query = params['q'].try(:first)
|
188
|
+
elsif referer_host == 'www.bing.com' and referer_path == '/search'
|
189
|
+
self.search_engine = 'Bing'
|
190
|
+
self.search_query = params['q'].try(:first)
|
191
|
+
elsif referer_host =~ /search\.yahoo\.com$/ and referer_path =~ /\/search;/
|
192
|
+
self.search_engine = 'Yahoo'
|
193
|
+
self.search_query = params['p'].try(:first)
|
194
|
+
elsif referer_host == 'www.baidu.com' and referer_path == '/s'
|
195
|
+
self.search_engine = 'Baidu'
|
196
|
+
self.search_query = params['wd'].try(:first)
|
197
|
+
elsif referer_host =~ /ask\.com$/ and referer_path =~ /^\/web/
|
198
|
+
self.search_engine = 'Ask'
|
199
|
+
self.search_query = params['q'].try(:first)
|
200
|
+
elsif referer_host == 'search.aol.com' and referer_path == '/aol/search'
|
201
|
+
self.search_engine = 'AOL'
|
202
|
+
self.search_query = params['q'].try(:first)
|
203
|
+
elsif referer_host =~ /metacrawler\.com$/ and referer_path =~ /search\/web/
|
204
|
+
self.search_engine = 'MetaCrawler'
|
205
|
+
self.search_query = params['q'].try(:first)
|
206
|
+
elsif referer_host =~ /dogpile\.com/ and referer_path =~ /dogpile\/ws\/results\/Web\//
|
207
|
+
self.search_engine = 'Dogpile'
|
208
|
+
void, self.search_query = referer_path.match(/ws\/results\/Web\/([^\/]*)\//).to_a
|
209
|
+
self.search_query = CGI::unescape(self.search_query).gsub('!FE', '.')
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Parse the params to fill param_id and format attributes
|
215
|
+
def params=(params)
|
216
|
+
self.param_id = params[:id]
|
217
|
+
self.format = params[:format]
|
218
|
+
end
|
219
|
+
|
220
|
+
# Init the corrosponding Gricer::Session (called before create)
|
221
|
+
#
|
222
|
+
# @return [Gricer::Session]
|
223
|
+
def init_session
|
224
|
+
if session
|
225
|
+
if session.updated_at < Time.now - ::Gricer.config.max_session_duration
|
226
|
+
self.session = Session.create previous_session: session, ip_address: @ip_address, agent: agent, requested_locale: @request_locale
|
227
|
+
else
|
228
|
+
self.session.touch
|
229
|
+
end
|
230
|
+
else
|
231
|
+
self.is_first_in_session = true
|
232
|
+
self.session = Session.create ip_address: @ip_address, agent: agent, requested_locale: @request_locale
|
233
|
+
self.session.touch
|
234
|
+
end
|
235
|
+
|
236
|
+
session
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,433 @@
|
|
1
|
+
module Gricer
|
2
|
+
# ActiveRecord Model for Session Statistics
|
3
|
+
# @attr [Gricer::Session] previous_session
|
4
|
+
# The current value of the associated previous session.
|
5
|
+
#
|
6
|
+
# @attr [Gricer::Agent] agent
|
7
|
+
# The current value of the associated agent.
|
8
|
+
#
|
9
|
+
# @attr [String] ip_address_hash
|
10
|
+
# The current value of the ip address in an anonyminized hash
|
11
|
+
#
|
12
|
+
# @attr [String] domain
|
13
|
+
# The current value of the domain (only major info) from which the session was requested.
|
14
|
+
#
|
15
|
+
# @attr [String] country
|
16
|
+
# The current value of the country from which the session was requested.
|
17
|
+
#
|
18
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
19
|
+
#
|
20
|
+
# @attr [String] region
|
21
|
+
# The current value of the region from which the session was requested.
|
22
|
+
#
|
23
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
24
|
+
#
|
25
|
+
# @attr [String] city
|
26
|
+
# The current value of the city from which the session was requested.
|
27
|
+
#
|
28
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
29
|
+
#
|
30
|
+
# @attr [String] postal_code
|
31
|
+
# The current value of the region from which the session was requested.
|
32
|
+
#
|
33
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
34
|
+
#
|
35
|
+
# @attr [Float] longitude
|
36
|
+
# The current value of the longitude of the city/region from which the session was requested.
|
37
|
+
#
|
38
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
39
|
+
#
|
40
|
+
# @attr [Float] latitude
|
41
|
+
# The current value of the latitude of the city/region from which the session was requested.
|
42
|
+
#
|
43
|
+
# You need to configure a GeoIP in the {Gricer::Config} instance.
|
44
|
+
#
|
45
|
+
# @attr [Boolean] javascript
|
46
|
+
# The current value of the javascript capability of the requesting agent.
|
47
|
+
#
|
48
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
49
|
+
#
|
50
|
+
# @attr [Boolean] java
|
51
|
+
# The current value of the java capability of the requesting agent.
|
52
|
+
#
|
53
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
54
|
+
#
|
55
|
+
# @attr [String] flash_version
|
56
|
+
# The current value of the version of flash installed on the requesting agent.
|
57
|
+
#
|
58
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
59
|
+
#
|
60
|
+
# @attr [String] flash_major_version
|
61
|
+
# The current value of the major version of flash installed on the requesting agent.
|
62
|
+
#
|
63
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
64
|
+
#
|
65
|
+
# @attr [String] silverlight_version
|
66
|
+
# The current value of the version of silverlight installed on the requesting agent.
|
67
|
+
#
|
68
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
69
|
+
#
|
70
|
+
# @attr [String] silverlight_major_version
|
71
|
+
# The current value of the major version of silverlight installed on the requesting agent.
|
72
|
+
#
|
73
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
74
|
+
#
|
75
|
+
# @attr [Integer] screen_width
|
76
|
+
# The current value of the width in pixels of the screen the requesting agent's window is on.
|
77
|
+
#
|
78
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
79
|
+
#
|
80
|
+
# @attr [Integer] screen_height
|
81
|
+
# The current value of the height in pixels of the screen the requesting agent's window is on.
|
82
|
+
#
|
83
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
84
|
+
#
|
85
|
+
# @attr [Integer] screen_depth
|
86
|
+
# The current value of the depth in bits of the screen the requesting agent's window is on.
|
87
|
+
#
|
88
|
+
# This feature needs the usage of {Gricer::TrackHelper#gricer_track_tag}.
|
89
|
+
#
|
90
|
+
# @attr [String] requested_locale_major
|
91
|
+
# The current value of the locale requested (major locale only)
|
92
|
+
#
|
93
|
+
# @attr [String] requested_locale_minor
|
94
|
+
# The current value of the locale requested (major locale only)
|
95
|
+
#
|
96
|
+
# @attr [String] requested_locale
|
97
|
+
# The current value of the locale requested
|
98
|
+
#
|
99
|
+
class Session < ::ActiveRecord::Base
|
100
|
+
set_table_name "#{::Gricer::config.table_name_prefix}sessions"
|
101
|
+
include ActiveModel::Statistics
|
102
|
+
|
103
|
+
has_many :requests, class_name: 'Gricer::Request', foreign_key: :session_id, order: 'created_at ASC'
|
104
|
+
belongs_to :agent, class_name: 'Gricer::Agent', foreign_key: :agent_id, counter_cache: true
|
105
|
+
belongs_to :previous_session, class_name: 'Gricer::Session', foreign_key: :previous_session_id
|
106
|
+
|
107
|
+
# Filter out anything that is not a Browser or MobileBrowser
|
108
|
+
# @return [ActiveRecord::Relation]
|
109
|
+
def self.browsers
|
110
|
+
self.includes("agent")
|
111
|
+
.where("\"#{Agent.table_name}\".\"agent_class_id\" IN (?)", [0x1000, 0x2000])
|
112
|
+
end
|
113
|
+
|
114
|
+
# Filter out only bounce sessions (sessions with just one request)
|
115
|
+
# @return [ActiveRecord::Relation]
|
116
|
+
def self.bounce_sessions
|
117
|
+
self.where("\"#{self.table_name}\".\"requests_count\" = ?", 1)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Filter out only new visits (which does not have a previous_session)
|
121
|
+
# @return [ActiveRecord::Relation]
|
122
|
+
def self.new_visits
|
123
|
+
where("\"#{self.table_name}\".\"previous_session_id\" IS NULL")
|
124
|
+
end
|
125
|
+
|
126
|
+
# This is just a list of two-part domain endings.
|
127
|
+
# It is used to get the domain from the request.
|
128
|
+
# return [Array]
|
129
|
+
def two_part_domain_endings
|
130
|
+
[
|
131
|
+
'com.ac','edu.ac','gov.ac','net.ac','mil.ac',
|
132
|
+
'org.ac','com.ae','net.ae','org.ae','gov.ae','ac.ae',
|
133
|
+
'co.ae','sch.ae','pro.ae','com.ai','org.ai','edu.ai',
|
134
|
+
'gov.ai','com.ar','net.ar','org.ar','gov.ar','mil.ar',
|
135
|
+
'edu.ar','int.ar','co.at','ac.at','or.at','gv.at','priv.at',
|
136
|
+
'com.au','gov.au','org.au','edu.au','id.au','oz.au',
|
137
|
+
'info.au','net.au','asn.au','csiro.au','telememo.au',
|
138
|
+
'conf.au','otc.au','com.az','net.az','org.az','com.bb',
|
139
|
+
'net.bb','org.bb','ac.be','belgie.be','dns.be','fgov.be',
|
140
|
+
'com.bh','gov.bh','net.bh','edu.bh','org.bh','com.bm',
|
141
|
+
'edu.bm','gov.bm','org.bm','net.bm','adm.br','adv.br',
|
142
|
+
'agr.br','am.br','arq.br','art.br','ato.br','bio.br',
|
143
|
+
'bmd.br','cim.br','cng.br','cnt.br','com.br','coop.br',
|
144
|
+
'ecn.br','edu.br','eng.br','esp.br','etc.br','eti.br',
|
145
|
+
'far.br','fm.br','fnd.br','fot.br','fst.br','g12.br',
|
146
|
+
'ggf.br','gov.br','imb.br','ind.br','inf.br','jor.br',
|
147
|
+
'lel.br','mat.br','med.br','mil.br','mus.br','net.br',
|
148
|
+
'nom.br','not.br','ntr.br','odo.br','org.br','ppg.br',
|
149
|
+
'pro.br','psc.br','psi.br','qsl.br','rec.br','slg.br',
|
150
|
+
'srv.br','tmp.br','trd.br','tur.br','tv.br','vet.br',
|
151
|
+
'zlg.br','com.bs','net.bs','org.bs','ab.ca','bc.ca',
|
152
|
+
'mb.ca','nb.ca','nf.ca','nl.ca','ns.ca','nt.ca','nu.ca',
|
153
|
+
'on.ca','pe.ca','qc.ca','sk.ca','yk.ca','gc.ca','co.ck',
|
154
|
+
'net.ck','org.ck','edu.ck','gov.ck','com.cn','edu.cn',
|
155
|
+
'gov.cn','net.cn','org.cn','ac.cn','ah.cn','bj.cn','cq.cn',
|
156
|
+
'gd.cn','gs.cn','gx.cn','gz.cn','hb.cn','he.cn','hi.cn',
|
157
|
+
'hk.cn','hl.cn','hn.cn','jl.cn','js.cn','ln.cn','mo.cn',
|
158
|
+
'nm.cn','nx.cn','qh.cn','sc.cn','sn.cn','sh.cn','sx.cn',
|
159
|
+
'tj.cn','tw.cn','xj.cn','xz.cn','yn.cn','zj.cn','arts.co',
|
160
|
+
'com.co','edu.co','firm.co','gov.co','info.co','int.co',
|
161
|
+
'nom.co','mil.co','org.co','rec.co','store.co','web.co',
|
162
|
+
'ac.cr','co.cr','ed.cr','fi.cr','go.cr','or.cr','sa.cr',
|
163
|
+
'com.cu','net.cu','org.cu','ac.cy','com.cy','gov.cy',
|
164
|
+
'net.cy','org.cy','co.dk','art.do','com.do','edu.do',
|
165
|
+
'gov.do','gob.do','org.do','mil.do','net.do','sld.do',
|
166
|
+
'web.do','com.dz','org.dz','net.dz','gov.dz','edu.dz',
|
167
|
+
'ass.dz','pol.dz','art.dz','com.ec','k12.ec','edu.ec',
|
168
|
+
'fin.ec','med.ec','gov.ec','mil.ec','org.ec','net.ec',
|
169
|
+
'com.ee','pri.ee','fie.ee','org.ee','med.ee','com.eg',
|
170
|
+
'edu.eg','eun.eg','gov.eg','net.eg','org.eg','sci.eg',
|
171
|
+
'com.er','net.er','org.er','edu.er','mil.er','gov.er',
|
172
|
+
'ind.er','com.es','org.es','gob.es','edu.es','nom.es',
|
173
|
+
'com.et','gov.et','org.et','edu.et','net.et','biz.et',
|
174
|
+
'name.et','info.et','ac.fj','com.fj','gov.fj','id.fj',
|
175
|
+
'org.fj','school.fj','com.fk','ac.fk','gov.fk','net.fk',
|
176
|
+
'nom.fk','org.fk','asso.fr','nom.fr','barreau.fr',
|
177
|
+
'com.fr','prd.fr','presse.fr','tm.fr','aeroport.fr',
|
178
|
+
'assedic.fr','avocat.fr','avoues.fr','cci.fr',
|
179
|
+
'chambagri.fr','chirurgiens-dentistes.fr',
|
180
|
+
'experts-comptables.fr','geometre-expert.fr',
|
181
|
+
'gouv.fr','greta.fr','huissier-justice.fr','medecin.fr',
|
182
|
+
'notaires.fr','pharmacien.fr','port.fr','veterinaire.fr',
|
183
|
+
'com.ge','edu.ge','gov.ge','mil.ge','net.ge','org.ge',
|
184
|
+
'pvt.ge','co.gg','org.gg','sch.gg','ac.gg','gov.gg',
|
185
|
+
'ltd.gg','ind.gg','net.gg','alderney.gg','guernsey.gg',
|
186
|
+
'sark.gg','com.gt','edu.gt','net.gt','gob.gt','org.gt',
|
187
|
+
'mil.gt','ind.gt','com.gu','edu.gu','net.gu','org.gu',
|
188
|
+
'gov.gu','mil.gu','com.hk','net.hk','org.hk','idv.hk',
|
189
|
+
'gov.hk','edu.hk','co.hu','2000.hu','erotika.hu',
|
190
|
+
'jogasz.hu','sex.hu','video.hu','info.hu','agrar.hu',
|
191
|
+
'film.hu','konyvelo.hu','shop.hu','org.hu','bolt.hu',
|
192
|
+
'forum.hu','lakas.hu','suli.hu','priv.hu','casino.hu',
|
193
|
+
'games.hu','media.hu','szex.hu','sport.hu','city.hu',
|
194
|
+
'hotel.hu','news.hu','tozsde.hu','tm.hu','erotica.hu',
|
195
|
+
'ingatlan.hu','reklam.hu','utazas.hu','ac.id','co.id',
|
196
|
+
'go.id','mil.id','net.id','or.id','co.il','net.il',
|
197
|
+
'org.il','ac.il','gov.il','k12.il','muni.il','idf.il',
|
198
|
+
'co.im','net.im','org.im','ac.im','lkd.co.im','gov.im',
|
199
|
+
'nic.im','plc.co.im','co.in','net.in','ac.in','ernet.in',
|
200
|
+
'gov.in','nic.in','res.in','gen.in','firm.in','mil.in',
|
201
|
+
'org.in','ind.in','ac.je','co.je','net.je','org.je',
|
202
|
+
'gov.je','ind.je','jersey.je','ltd.je','sch.je','com.jo',
|
203
|
+
'org.jo','net.jo','gov.jo','edu.jo','mil.jo','ad.jp',
|
204
|
+
'ac.jp','co.jp','go.jp','or.jp','ne.jp','gr.jp','ed.jp',
|
205
|
+
'lg.jp','net.jp','org.jp','gov.jp','hokkaido.jp',
|
206
|
+
'aomori.jp','iwate.jp','miyagi.jp','akita.jp',
|
207
|
+
'yamagata.jp','fukushima.jp','ibaraki.jp','tochigi.jp',
|
208
|
+
'gunma.jp','saitama.jp','chiba.jp','tokyo.jp',
|
209
|
+
'kanagawa.jp','niigata.jp','toyama.jp','ishikawa.jp',
|
210
|
+
'fukui.jp','yamanashi.jp','nagano.jp','gifu.jp',
|
211
|
+
'shizuoka.jp','aichi.jp','mie.jp','shiga.jp','kyoto.jp',
|
212
|
+
'osaka.jp','hyogo.jp','nara.jp','wakayama.jp','tottori.jp',
|
213
|
+
'shimane.jp','okayama.jp','hiroshima.jp','yamaguchi.jp',
|
214
|
+
'tokushima.jp','kagawa.jp','ehime.jp','kochi.jp',
|
215
|
+
'fukuoka.jp','saga.jp','nagasaki.jp','kumamoto.jp',
|
216
|
+
'oita.jp','miyazaki.jp','kagoshima.jp','okinawa.jp',
|
217
|
+
'sapporo.jp','sendai.jp','yokohama.jp','kawasaki.jp',
|
218
|
+
'nagoya.jp','kobe.jp','kitakyushu.jp','utsunomiya.jp',
|
219
|
+
'kanazawa.jp','takamatsu.jp','matsuyama.jp','com.kh',
|
220
|
+
'net.kh','org.kh','per.kh','edu.kh','gov.kh','mil.kh',
|
221
|
+
'ac.kr','co.kr','go.kr','ne.kr','or.kr','pe.kr','re.kr',
|
222
|
+
'seoul.kr','kyonggi.kr','com.kw','net.kw','org.kw',
|
223
|
+
'edu.kw','gov.kw','com.la','net.la','org.la','com.lb',
|
224
|
+
'org.lb','net.lb','edu.lb','gov.lb','mil.lb','com.lc',
|
225
|
+
'edu.lc','gov.lc','net.lc','org.lc','com.lv','net.lv',
|
226
|
+
'org.lv','edu.lv','gov.lv','mil.lv','id.lv','asn.lv',
|
227
|
+
'conf.lv','com.ly','net.ly','org.ly','co.ma','net.ma',
|
228
|
+
'org.ma','press.ma','ac.ma','com.mk','com.mm','net.mm',
|
229
|
+
'org.mm','edu.mm','gov.mm','com.mo','net.mo','org.mo',
|
230
|
+
'edu.mo','gov.mo','com.mt','net.mt','org.mt','edu.mt',
|
231
|
+
'tm.mt','uu.mt','com.mx','net.mx','org.mx','com.my',
|
232
|
+
'org.my','gov.my','edu.my','net.my','com.na','org.na',
|
233
|
+
'net.na','alt.na','edu.na','cul.na','unam.na','telecom.na',
|
234
|
+
'com.nc','net.nc','org.nc','ac.ng','edu.ng','sch.ng',
|
235
|
+
'com.ng','gov.ng','org.ng','net.ng','gob.ni','com.ni',
|
236
|
+
'net.ni','edu.ni','nom.ni','org.ni','com.np','net.np',
|
237
|
+
'org.np','gov.np','edu.np','ac.nz','co.nz','cri.nz',
|
238
|
+
'gen.nz','geek.nz','govt.nz','iwi.nz','maori.nz','mil.nz',
|
239
|
+
'net.nz','org.nz','school.nz','com.om','co.om','edu.om',
|
240
|
+
'ac.om','gov.om','net.om','org.om','mod.om','museum.om',
|
241
|
+
'biz.om','pro.om','med.om','com.pa','net.pa','org.pa',
|
242
|
+
'edu.pa','ac.pa','gob.pa','sld.pa','edu.pe','gob.pe',
|
243
|
+
'nom.pe','mil.pe','org.pe','com.pe','net.pe','com.pg',
|
244
|
+
'net.pg','ac.pg','com.ph','net.ph','org.ph','mil.ph',
|
245
|
+
'ngo.ph','aid.pl','agro.pl','atm.pl','auto.pl','biz.pl',
|
246
|
+
'com.pl','edu.pl','gmina.pl','gsm.pl','info.pl','mail.pl',
|
247
|
+
'miasta.pl','media.pl','mil.pl','net.pl',
|
248
|
+
'nieruchomosci.pl','nom.pl','org.pl','pc.pl','powiat.pl',
|
249
|
+
'priv.pl','realestate.pl','rel.pl','sex.pl','shop.pl',
|
250
|
+
'sklep.pl','sos.pl','szkola.pl','targi.pl','tm.pl',
|
251
|
+
'tourism.pl','travel.pl','turystyka.pl','com.pk','net.pk',
|
252
|
+
'edu.pk','org.pk','fam.pk','biz.pk','web.pk','gov.pk',
|
253
|
+
'gob.pk','gok.pk','gon.pk','gop.pk','gos.pk','edu.ps',
|
254
|
+
'gov.ps','plo.ps','sec.ps','com.py','net.py','org.py',
|
255
|
+
'edu.py','com.qa','net.qa','org.qa','edu.qa','gov.qa',
|
256
|
+
'asso.re','com.re','nom.re','com.ro','org.ro','tm.ro',
|
257
|
+
'nt.ro','nom.ro','info.ro','rec.ro','arts.ro','firm.ro',
|
258
|
+
'store.ro','www.ro','com.ru','net.ru','org.ru','gov.ru',
|
259
|
+
'pp.ru','com.sa','edu.sa','sch.sa','med.sa','gov.sa',
|
260
|
+
'net.sa','org.sa','pub.sa','com.sb','net.sb','org.sb',
|
261
|
+
'edu.sb','gov.sb','com.sd','net.sd','org.sd','edu.sd',
|
262
|
+
'sch.sd','med.sd','gov.sd','tm.se','press.se','parti.se',
|
263
|
+
'brand.se','fh.se','fhsk.se','fhv.se','komforb.se',
|
264
|
+
'kommunalforbund.se','komvux.se','lanarb.se','lanbib.se',
|
265
|
+
'naturbruksgymn.se','sshn.se','org.se','pp.se','com.sg',
|
266
|
+
'net.sg','org.sg','edu.sg','gov.sg','per.sg','com.sh',
|
267
|
+
'net.sh','org.sh','edu.sh','gov.sh','mil.sh','gov.st',
|
268
|
+
'saotome.st','principe.st','consulado.st','embaixada.st',
|
269
|
+
'org.st','edu.st','net.st','com.st','store.st','mil.st',
|
270
|
+
'co.st','com.sv','org.sv','edu.sv','gob.sv','red.sv',
|
271
|
+
'com.sy','net.sy','org.sy','gov.sy','ac.th','co.th',
|
272
|
+
'go.th','net.th','or.th','com.tn','net.tn','org.tn',
|
273
|
+
'edunet.tn','gov.tn','ens.tn','fin.tn','nat.tn','ind.tn',
|
274
|
+
'info.tn','intl.tn','rnrt.tn','rnu.tn','rns.tn',
|
275
|
+
'tourism.tn','com.tr','net.tr','org.tr','edu.tr','gov.tr',
|
276
|
+
'mil.tr','bbs.tr','k12.tr','gen.tr','co.tt','com.tt',
|
277
|
+
'org.tt','net.tt','biz.tt','info.tt','pro.tt','name.tt',
|
278
|
+
'gov.tt','edu.tt','nic.tt','us.tt','uk.tt','ca.tt','eu.tt',
|
279
|
+
'es.tt','fr.tt','it.tt','se.tt','dk.tt','be.tt','de.tt',
|
280
|
+
'at.tt','au.tt','co.tv','com.tw','net.tw','org.tw',
|
281
|
+
'edu.tw','idv.tw','gove.tw','com.ua','net.ua','org.ua',
|
282
|
+
'edu.ua','gov.ua','ac.ug','co.ug','or.ug','go.ug','co.uk',
|
283
|
+
'me.uk','org.uk','edu.uk','ltd.uk','plc.uk','net.uk',
|
284
|
+
'sch.uk','nic.uk','ac.uk','gov.uk','nhs.uk','police.uk',
|
285
|
+
'mod.uk','dni.us','fed.us','com.uy','edu.uy','net.uy',
|
286
|
+
'org.uy','gub.uy','mil.uy','com.ve','net.ve','org.ve',
|
287
|
+
'co.ve','edu.ve','gov.ve','mil.ve','arts.ve','bib.ve',
|
288
|
+
'firm.ve','info.ve','int.ve','nom.ve','rec.ve','store.ve',
|
289
|
+
'tec.ve','web.ve','co.vi','net.vi','org.vi','com.vn',
|
290
|
+
'biz.vn','edu.vn','gov.vn','net.vn','org.vn','int.vn',
|
291
|
+
'ac.vn','pro.vn','info.vn','health.vn','name.vn','com.vu',
|
292
|
+
'edu.vu','net.vu','org.vu','de.vu','ch.vu','fr.vu',
|
293
|
+
'com.ws','net.ws','org.ws','gov.ws','edu.ws','ac.yu',
|
294
|
+
'co.yu','edu.yu','org.yu','com.ye','net.ye','org.ye',
|
295
|
+
'gov.ye','edu.ye','mil.ye','ac.za','alt.za','bourse.za',
|
296
|
+
'city.za','co.za','edu.za','gov.za','law.za','mil.za',
|
297
|
+
'net.za','ngo.za','nom.za','org.za','school.za','tm.za',
|
298
|
+
'web.za','co.zw','ac.zw','org.zw','gov.zw','eu.org',
|
299
|
+
'au.com','br.com','cn.com','de.com','de.net','eu.com',
|
300
|
+
'gb.com','gb.net','hu.com','no.com','qc.com','ru.com',
|
301
|
+
'sa.com','se.com','uk.com','uk.net','us.com','uy.com',
|
302
|
+
'za.com','dk.org','tel.no','fax.nr','mob.nr','mobil.nr',
|
303
|
+
'mobile.nr','tel.nr','tlf.nr','e164.arpa'
|
304
|
+
]
|
305
|
+
end
|
306
|
+
|
307
|
+
# Parse the requesting IP address and fill corrosponding attributes
|
308
|
+
# @param ip [String] An IP address (IPv4 only at the moment)
|
309
|
+
def ip_address=(ip)
|
310
|
+
require 'digest/sha1'
|
311
|
+
require 'resolv'
|
312
|
+
|
313
|
+
logger.debug("IP: #{ip}")
|
314
|
+
|
315
|
+
unless ip.blank?
|
316
|
+
self.ip_address_hash = Digest::SHA1.hexdigest(ip)
|
317
|
+
|
318
|
+
# IP
|
319
|
+
begin
|
320
|
+
domain_parts = Resolv.getname(ip).split('.')
|
321
|
+
|
322
|
+
self.domain = "#{domain_parts[-1]}"
|
323
|
+
|
324
|
+
self.domain = "#{domain_parts[-2]}.#{domain}" if domain_parts[-2]
|
325
|
+
|
326
|
+
if two_part_domain_endings.include? self.domain
|
327
|
+
self.domain = "#{domain_parts[-3]}.#{self.domain}"
|
328
|
+
end
|
329
|
+
rescue
|
330
|
+
ip_parts = ip.split('.')
|
331
|
+
self.domain = "#{ip_parts[0]}.#{ip_parts[1]}.x.x"
|
332
|
+
end
|
333
|
+
|
334
|
+
# GeoIP
|
335
|
+
if ::Gricer.config.geoip_db
|
336
|
+
if Rails.env.development?
|
337
|
+
geoip = {:country_code=>"DE", :country_code3=>"DEU", :country_name=>"Germany", :latitude=>51.0, :longitude=>9.0}
|
338
|
+
else
|
339
|
+
geoip = ::Gricer.config.geoip_db.look_up(ip)
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
if geoip
|
344
|
+
self.country = geoip[:country_code].try(:downcase)
|
345
|
+
self.region = geoip[:region].try(:downcase)
|
346
|
+
self.city = geoip[:city]
|
347
|
+
self.postal_code = geoip[:postal_code]
|
348
|
+
self.longitude = geoip[:longitude]
|
349
|
+
self.latitude = geoip[:latitude]
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
def requested_locale=(locale)
|
356
|
+
self.requested_locale_major, self.requested_locale_minor = locale.try(:downcase).try(:split, '-')
|
357
|
+
end
|
358
|
+
|
359
|
+
def requested_locale
|
360
|
+
if requested_locale_minor
|
361
|
+
"#{requested_locale_major}-#{requested_locale_minor}"
|
362
|
+
else
|
363
|
+
requested_locale_major
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
def silverlight_version=(version)
|
368
|
+
self[:silverlight_version] = version
|
369
|
+
self.silverlight_major_version = silverlight_version.match(/^([0-9]*\.[0-9]*)/).to_a.last if silverlight_version
|
370
|
+
end
|
371
|
+
|
372
|
+
def flash_version=(version)
|
373
|
+
self[:flash_version] = version
|
374
|
+
self.flash_major_version = flash_version.match(/^([0-9]*\.[0-9]*)/).to_a.last if flash_version
|
375
|
+
end
|
376
|
+
|
377
|
+
# Get the bounce rate
|
378
|
+
#
|
379
|
+
# This is the rate of sessions with one request to sessions with multiple requests.
|
380
|
+
# @return [Float]
|
381
|
+
def self.bounce_rate
|
382
|
+
if (c = self.count) > 0
|
383
|
+
self.bounce_sessions.count / c.to_f
|
384
|
+
else
|
385
|
+
0
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
# Get the average count of requests per session.
|
390
|
+
#
|
391
|
+
# @return [Float]
|
392
|
+
def self.requests_per_session
|
393
|
+
if (c = self.count) > 0
|
394
|
+
self.sum(:requests_count) / c.to_f
|
395
|
+
else
|
396
|
+
0
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# Get the average duration of sessions in seconds.
|
401
|
+
#
|
402
|
+
# @return [Float]
|
403
|
+
def self.avg_duration
|
404
|
+
if (c = self.count) > 0
|
405
|
+
logger.debug ActiveRecord::Base.connection.class
|
406
|
+
|
407
|
+
if ActiveRecord::Base.connection.class.to_s == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
|
408
|
+
self.sum("date_part('epoch', \"#{self.table_name}\".\"updated_at\") - date_part('epoch', \"#{self.table_name}\".\"created_at\")").to_f / c.to_f
|
409
|
+
else
|
410
|
+
self.sum("strftime('%s', \"#{self.table_name}\".\"updated_at\") - strftime('%s', \"#{self.table_name}\".\"created_at\")") / c.to_f
|
411
|
+
end
|
412
|
+
else
|
413
|
+
0
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
# Get the duration of the current session instance
|
418
|
+
def duration
|
419
|
+
updated_at - created_at
|
420
|
+
end
|
421
|
+
|
422
|
+
# Get the new visitor rate
|
423
|
+
#
|
424
|
+
# This is the rate of new sessions to all sessions
|
425
|
+
def self.new_visitors
|
426
|
+
if (c = self.count) > 0
|
427
|
+
self.new_visits.count / c.to_f
|
428
|
+
else
|
429
|
+
0
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|