redis_analytics 0.7.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/views/layouts/redis_analytics/application.html.erb +3 -3
- data/coverage/index.html +423 -381
- data/lib/redis_analytics/configuration.rb +73 -73
- data/lib/redis_analytics/engine.rb +7 -0
- data/lib/redis_analytics/filter.rb +22 -22
- data/lib/redis_analytics/helpers.rb +58 -58
- data/lib/redis_analytics/metrics.rb +73 -73
- data/lib/redis_analytics/version.rb +3 -3
- data/lib/redis_analytics/visit.rb +96 -96
- data/test/dummy/config/environments/production.rb +1 -1
- data/test/dummy/config/routes.rb +1 -1
- data/test/dummy/log/development.log +1185 -0
- data/test/dummy/log/production.log +5172 -0
- data/test/dummy/public/assets/application-c900658d554ff9f314a2e1b97cd68997.js.gz +0 -0
- data/test/dummy/public/assets/manifest-567012ae8b6f03148f7121062750991f.json +1 -0
- data/test/dummy/public/assets/redis_analytics/redis_analytics-82322234eccfd3d7c55a2034ee41ab2a.js +10785 -0
- data/test/dummy/public/assets/redis_analytics/redis_analytics-82322234eccfd3d7c55a2034ee41ab2a.js.gz +0 -0
- data/test/dummy/public/assets/redis_analytics/redis_analytics-f13abe0904b7483ea8c8c08029e97be3.css +64 -0
- data/test/dummy/public/assets/redis_analytics/redis_analytics-f13abe0904b7483ea8c8c08029e97be3.css.gz +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/3b2603753f496fe7b73a04ce200ea6c0 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/4b838eac074ecce8b8ae19c261677ab6 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/63afa0e9c559fa85d5c63b6f37728141 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/6d0077b1948c42a8892f40120649d217 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/a317f594a79c3dd49a6f88b49aabc1b5 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/f069f087fa68223029e7fb8547e5bc3b +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/006eb7cc017cf18c3ea32cab97f0cc3c +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/192691b9e0bedebfde12633bb3629d0b +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/3b2603753f496fe7b73a04ce200ea6c0 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/4b838eac074ecce8b8ae19c261677ab6 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/5cf60638cb580f41112a5a83eb3b72ef +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/63afa0e9c559fa85d5c63b6f37728141 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/6c2f18f7338d56feecce32780357521c +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/6d0077b1948c42a8892f40120649d217 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/7751914469530dae0646d92467e9d72e +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/8d62150b658b3a8b6fed7e8951f52392 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/8ea331810c31cbe1ba34b91a02f769e7 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/953bc37b1ee0915247dba29773960202 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/9b54afa4ef026f4c288feeec49f2f526 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/a29d0dc527ff5ce1252ccf6370514620 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/a317f594a79c3dd49a6f88b49aabc1b5 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/b01583a39abd5ce0a3d2b2967c6f75bd +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/cfdf466647e83eb93e0d6630e4b51a25 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/d7491740e7757fe2ec57fd6d25461e5c +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/df16db3bfcc56fafc73b853b7999be1f +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/e7bd439b274a2155050b47e5a64ea72d +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/f069f087fa68223029e7fb8547e5bc3b +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/dummy/tmp/cache/assets/production/sprockets/f9a412f49281cc7e6512f0787f7ba05f +0 -0
- data/vendor/assets/javascripts/redis_analytics/{engine.js → redis_analytics.js} +6 -1
- data/vendor/assets/stylesheets/redis_analytics/{engine.css → redis_analytics.css} +3 -1
- metadata +43 -8
- data/app/views/redis_analytics/application/_footer.html.erb~ +0 -3
- data/app/views/redis_analytics/visits/_unique_visits_line.html.erb~ +0 -26
- data/app/views/redis_analytics/visits/index.html.erb~ +0 -71
- data/test/dummy/public/assets/manifest-5bcba723c313582b1d428fc3bf592b29.json +0 -1
@@ -1,101 +1,101 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module RedisAnalytics
|
2
|
+
module Configuration
|
3
|
+
# Redis connection instance
|
4
|
+
attr_accessor :redis_connection
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
# Redis namespace for keys
|
7
|
+
attr_writer :redis_namespace
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
# Name of the cookie which tracks first visitors
|
10
|
+
attr_writer :first_visit_cookie_name
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
# Name of the cookie which tracks current visits
|
13
|
+
attr_writer :current_visit_cookie_name
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
# Minutes the visit should timeout after (if no hit is received)
|
16
|
+
attr_writer :visit_timeout
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
# Endpoint for dashboard
|
19
|
+
attr_writer :dashboard_endpoint
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
# Endpoint for api
|
22
|
+
attr_writer :api_endpoint
|
23
23
|
|
24
|
-
|
24
|
+
attr_writer :path_filters
|
25
25
|
|
26
|
-
|
26
|
+
attr_writer :filters
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
# Path to the Geo IP Database file
|
29
|
+
attr_writer :geo_ip_data_path
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
# Minutes the visit should timeout after (if no hit is received)
|
37
|
-
def visit_timeout
|
38
|
-
@visit_timeout ||= 30 # minutes
|
39
|
-
end
|
31
|
+
# Redis namespace for keys
|
32
|
+
def redis_namespace
|
33
|
+
@redis_namespace ||= 'ra'
|
34
|
+
end
|
40
35
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
# Minutes the visit should timeout after (if no hit is received)
|
37
|
+
def visit_timeout
|
38
|
+
@visit_timeout ||= 30 # minutes
|
39
|
+
end
|
45
40
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
# Name of the cookie which tracks first visitors (unknown visitors)
|
42
|
+
def first_visit_cookie_name
|
43
|
+
@first_visit_cookie_name ||= '_rucn'
|
44
|
+
end
|
50
45
|
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
# Name of the cookie which tracks visits
|
47
|
+
def current_visit_cookie_name
|
48
|
+
@current_visit_cookie_name ||= '_vcn'
|
49
|
+
end
|
54
50
|
|
55
|
-
|
56
|
-
|
57
|
-
|
51
|
+
def filters
|
52
|
+
@filters ||= []
|
53
|
+
end
|
58
54
|
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
def path_filters
|
56
|
+
@path_filters ||= []
|
57
|
+
end
|
62
58
|
|
63
|
-
|
64
|
-
|
65
|
-
|
59
|
+
def add_filter(&proc)
|
60
|
+
filters << RedisAnalytics::Filter.new(proc)
|
61
|
+
end
|
66
62
|
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
def add_path_filter(path)
|
64
|
+
path_filters << RedisAnalytics::PathFilter.new(path)
|
65
|
+
end
|
70
66
|
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
def geo_ip_data_path
|
68
|
+
@geo_ip_data_path = ::File.expand_path(::File.join(::File.dirname(__FILE__),'..','..')) + "/bin/GeoIP.dat"
|
69
|
+
end
|
74
70
|
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
def visitor_recency_slices
|
72
|
+
@visitor_recency_slices ||= [1, 7, 30]
|
73
|
+
end
|
78
74
|
|
79
|
-
|
80
|
-
|
81
|
-
|
75
|
+
def default_range
|
76
|
+
@default_range = :day
|
77
|
+
end
|
82
78
|
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
def redis_key_timestamps # [format, expire in seconds or nil]
|
80
|
+
['%Y', '%Y_%m', '%Y_%m_%d', '%Y_%m_%d_%H', '%Y_%m_%d_%H_%M']
|
81
|
+
end
|
86
82
|
|
87
|
-
|
88
|
-
|
89
|
-
|
83
|
+
def time_range_formats
|
84
|
+
[[:year, :month, "%b"], [:week, :day, "%a"], [:day, :hour, "%l%P"]]
|
85
|
+
end
|
90
86
|
|
91
|
-
|
92
|
-
|
93
|
-
|
87
|
+
def configure
|
88
|
+
yield self
|
89
|
+
end
|
94
90
|
|
95
|
-
|
96
|
-
|
97
|
-
|
91
|
+
def api_endpoint
|
92
|
+
@api_endpoint || dashboard_endpoint + '/api'
|
93
|
+
end
|
98
94
|
|
95
|
+
def dashboard_endpoint
|
96
|
+
@dashboard_endpoint || '/redis_analytics'
|
99
97
|
end
|
98
|
+
|
100
99
|
end
|
100
|
+
end
|
101
101
|
|
@@ -13,6 +13,13 @@ module RedisAnalytics
|
|
13
13
|
initializer "redis_analytics.view_helpers" do |app|
|
14
14
|
ActionController::Base.send :include, RedisAnalytics::Helpers
|
15
15
|
end
|
16
|
+
|
17
|
+
initializer "redis_analytics.precompile.hook", group: :all do |app|
|
18
|
+
app.config.assets.precompile += %w[
|
19
|
+
redis_analytics/redis_analytics.js
|
20
|
+
redis_analytics/redis_analytics.css
|
21
|
+
]
|
22
|
+
end
|
16
23
|
end
|
17
24
|
end
|
18
25
|
end
|
@@ -1,32 +1,32 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
module RedisAnalytics
|
2
|
+
class Filter
|
3
|
+
attr_reader :filter_proc
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def matches?(request, response)
|
10
|
-
filter_proc.call(request, response)
|
11
|
-
end
|
5
|
+
def initialize(filter_proc)
|
6
|
+
@filter_proc = filter_proc
|
7
|
+
end
|
12
8
|
|
9
|
+
def matches?(request, response)
|
10
|
+
filter_proc.call(request, response)
|
13
11
|
end
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
end
|
14
|
+
|
15
|
+
class PathFilter
|
16
|
+
attr_reader :filter_path
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def initialize(filter_path)
|
19
|
+
@filter_path = filter_path
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
22
|
+
def matches?(request_path)
|
23
|
+
if filter_path.is_a?(String)
|
24
|
+
request_path == filter_path
|
25
|
+
elsif filter_path.is_a?(Regexp)
|
26
|
+
request_path =~ filter_path
|
28
27
|
end
|
29
28
|
end
|
30
|
-
|
31
29
|
end
|
32
30
|
|
31
|
+
end
|
32
|
+
|
@@ -1,74 +1,74 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module RedisAnalytics
|
2
|
+
module Helpers
|
3
3
|
|
4
|
-
|
4
|
+
FORMAT_SPECIFIER = [['%Y', 365], ['%m', 30], ['%d', 24], ['%H', 60], ['%M', 60]]
|
5
5
|
|
6
|
-
|
6
|
+
GRANULARITY = ['yearly', 'monthly', 'dayly', 'hourly', 'minutely']
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
8
|
+
private
|
9
|
+
def method_missing(meth, *args, &block)
|
10
|
+
if meth.to_s =~ /^(minute|hour|dai|day|month|year)ly_([a-z_0-9]+)$/
|
11
|
+
granularity = ($1 == 'dai' ? 'day' : $1) + 'ly'
|
12
|
+
metric_name = $2
|
13
|
+
data(granularity, metric_name, *args)
|
14
|
+
else
|
15
|
+
super
|
17
16
|
end
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
def metric_type(metric_name)
|
20
|
+
RedisAnalytics.redis_connection.hget("#{RedisAnalytics.redis_namespace}:#METRICS", metric_name)
|
21
|
+
end
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
def data(granularity, metric_name, from_date, options = {})
|
24
|
+
aggregate = options[:aggregate] || false
|
25
|
+
x = granularity[0..-3]
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
to_date = (options[:to_date] || Time.now).send("end_of_#{x}")
|
28
|
+
i = from_date.send("beginning_of_#{x}")
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
else
|
52
|
-
return time.zip(RedisAnalytics.redis_connection.mget(*union).map(&:to_i))
|
53
|
-
end
|
30
|
+
union = []
|
31
|
+
time = []
|
32
|
+
begin
|
33
|
+
slice_key = i.strftime(FORMAT_SPECIFIER[0..GRANULARITY.index(granularity)].map{|x| x[0]}.join('_'))
|
34
|
+
union << "#{RedisAnalytics.redis_namespace}:#{metric_name}:#{slice_key}"
|
35
|
+
time << slice_key.split('_')
|
36
|
+
i += 1.send(x)
|
37
|
+
end while i <= to_date
|
38
|
+
seq = get_next_seq
|
39
|
+
if metric_type(metric_name) == 'String'
|
40
|
+
if aggregate
|
41
|
+
union_key = "#{RedisAnalytics.redis_namespace}:#{seq}"
|
42
|
+
RedisAnalytics.redis_connection.zunionstore(union_key, union)
|
43
|
+
RedisAnalytics.redis_connection.expire(union_key, 100)
|
44
|
+
return Hash[RedisAnalytics.redis_connection.zrange(union_key, 0, -1, :with_scores => true)]
|
45
|
+
else
|
46
|
+
return time.zip(union.map{|x| Hash[RedisAnalytics.redis_connection.zrange(x, 0, -1, :with_scores => true)]})
|
47
|
+
end
|
48
|
+
elsif metric_type(metric_name) == 'Fixnum'
|
49
|
+
if aggregate
|
50
|
+
return RedisAnalytics.redis_connection.mget(*union).map(&:to_i).inject(:+)
|
54
51
|
else
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
52
|
+
return time.zip(RedisAnalytics.redis_connection.mget(*union).map(&:to_i))
|
53
|
+
end
|
54
|
+
else
|
55
|
+
if Metrics.public_instance_methods.any?{|m| m.to_s =~ /^#{metric_name}_ratio_per_(hit|visit)$/}
|
56
|
+
aggregate ? {} : time.zip([{}] * time.length)
|
57
|
+
elsif Metrics.public_instance_methods.any?{|m| m.to_s =~ /^#{metric_name}_count_per_(hit|visit)$/}
|
58
|
+
aggregate ? 0 : time.zip([0] * time.length)
|
59
|
+
else
|
60
|
+
aggregate ? 0 : time.zip([0] * time.length)
|
62
61
|
end
|
63
62
|
end
|
63
|
+
end
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
def get_next_seq
|
66
|
+
seq = RedisAnalytics.redis_connection.incr("#{RedisAnalytics.redis_namespace}:#SEQUENCER")
|
67
|
+
end
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
end
|
69
|
+
def time_range
|
70
|
+
(request.cookies["_rarng"] || RedisAnalytics.default_range).to_sym
|
72
71
|
end
|
73
72
|
end
|
73
|
+
end
|
74
74
|
|
@@ -1,95 +1,95 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module RedisAnalytics
|
2
|
+
module Metrics
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
attr_reader :visit_time_count_per_visit
|
5
|
+
attr_reader :visits_count_per_visit, :first_visits_count_per_visit, :repeat_visits_count_per_visit
|
6
|
+
attr_reader :unique_visits_ratio_per_visit
|
7
|
+
attr_reader :page_views_count_per_hit, :second_page_views_count_per_hit
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
# Developers can override or define new public methods here
|
10
|
+
# Methods should start with track and end with count or types
|
11
|
+
# Return types should be Fixnum or String resp.
|
12
|
+
# If you return nil or an error nothing will be tracked
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def browser_ratio_per_visit
|
15
|
+
user_agent.name.to_s
|
16
|
+
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def platform_ratio_per_visit
|
19
|
+
user_agent.platform.to_s
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
rescue Exception => e
|
31
|
-
warn "Unable to fetch country info #{e}"
|
22
|
+
def country_ratio_per_visit
|
23
|
+
if defined?(GeoIP)
|
24
|
+
begin
|
25
|
+
g = GeoIP.new(RedisAnalytics.geo_ip_data_path)
|
26
|
+
geo_country_code = g.country(@rack_request.ip).to_hash[:country_code2]
|
27
|
+
if geo_country_code and geo_country_code =~ /^[A-Z]{2}$/
|
28
|
+
return geo_country_code
|
32
29
|
end
|
30
|
+
rescue Exception => e
|
31
|
+
warn "Unable to fetch country info #{e}"
|
33
32
|
end
|
34
33
|
end
|
34
|
+
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
36
|
+
def recency_ratio_per_visit
|
37
|
+
# tracking for visitor recency
|
38
|
+
if @last_visit_time # from first_visit_cookie
|
39
|
+
days_since_last_visit = ((@t.to_i - @last_visit_time.to_i)/(24*3600)).round
|
40
|
+
if days_since_last_visit <= 1
|
41
|
+
return 'd'
|
42
|
+
elsif days_since_last_visit <= 7
|
43
|
+
return 'w'
|
44
|
+
elsif days_since_last_visit <= 30
|
45
|
+
return 'm'
|
46
|
+
else
|
47
|
+
return 'o'
|
49
48
|
end
|
50
49
|
end
|
50
|
+
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
def device_ratio_per_visit
|
53
|
+
return ((user_agent.mobile? or user_agent.tablet?) ? 'mobile' : 'desktop')
|
54
|
+
end
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
56
|
+
def referrer_ratio_per_visit
|
57
|
+
if @rack_request.referrer
|
58
|
+
['google', 'bing', 'yahoo', 'cleartrip', 'github'].each do |referrer|
|
59
|
+
# this will track x.google.mysite.com as google so its buggy, fix the regex
|
60
|
+
if m = @rack_request.referrer.match(/^(https?:\/\/)?([a-zA-Z0-9\.\-]+\.)?(#{referrer})\.([a-zA-Z\.]+)(:[0-9]+)?(\/.*)?$/)
|
61
|
+
"REFERRER => #{m.to_a[3]}"
|
62
|
+
referrer = m.to_a[3]
|
63
|
+
else
|
64
|
+
referrer = 'other'
|
66
65
|
end
|
67
|
-
else
|
68
|
-
referrer = 'organic'
|
69
66
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
# track the ratio of URL's visits
|
74
|
-
def url_ratio_per_hit
|
75
|
-
return @rack_request.path
|
76
|
-
end
|
77
|
-
|
78
|
-
# track the landing pages ratio
|
79
|
-
def landing_page_ratio_per_hit
|
80
|
-
return @rack_request.path if @page_view_seq_no.to_i == 0
|
67
|
+
else
|
68
|
+
referrer = 'organic'
|
81
69
|
end
|
70
|
+
return referrer
|
71
|
+
end
|
82
72
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
73
|
+
# track the ratio of URL's visits
|
74
|
+
def url_ratio_per_hit
|
75
|
+
return @rack_request.path
|
76
|
+
end
|
77
|
+
|
78
|
+
# track the landing pages ratio
|
79
|
+
def landing_page_ratio_per_hit
|
80
|
+
return @rack_request.path if @page_view_seq_no.to_i == 0
|
81
|
+
end
|
87
82
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
83
|
+
# track the landing pages ratio
|
84
|
+
def http_response_ratio_per_hit
|
85
|
+
return @rack_response.status.to_s
|
86
|
+
end
|
92
87
|
|
88
|
+
private
|
89
|
+
def user_agent
|
90
|
+
Browser.new(:ua => @rack_request.user_agent, :accept_language => 'en-us')
|
93
91
|
end
|
92
|
+
|
94
93
|
end
|
94
|
+
end
|
95
95
|
|