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 @@
|
|
1
|
+
<%= params.inspect %>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<div class='overview'>
|
2
|
+
<h2>
|
3
|
+
Overview for <%=l @stat_from%>
|
4
|
+
<% unless @stat_from == @stat_thru -%>
|
5
|
+
to <%=l @stat_thru%>
|
6
|
+
<% end -%>
|
7
|
+
</h2>
|
8
|
+
|
9
|
+
<p>
|
10
|
+
<% sessions_count = sessions.count.try(:to_f) -%>
|
11
|
+
<%=t '.sessions', count: sessions_count.to_i %>
|
12
|
+
</p>
|
13
|
+
<p>
|
14
|
+
<%=t '.new_sessions', count: sessions.new_visits.count %>
|
15
|
+
</p>
|
16
|
+
<p>
|
17
|
+
<%=t '.new_visitors', percentage: format_percentage(sessions.new_visitors) %>
|
18
|
+
</p>
|
19
|
+
<p>
|
20
|
+
<% request_count = requests.count.try(:to_f) -%>
|
21
|
+
<%=t '.requests', count: request_count.to_i %>
|
22
|
+
</p>
|
23
|
+
<p>
|
24
|
+
<%=t '.requests_per_session', count: '%3.2f' % sessions.requests_per_session %>
|
25
|
+
</p>
|
26
|
+
|
27
|
+
<p>
|
28
|
+
<%=t '.bounce_rate', percentage: format_percentage(sessions.bounce_rate) %>
|
29
|
+
</p>
|
30
|
+
<p>
|
31
|
+
<%=t '.avg_duration', time: format_seconds(sessions.avg_duration) %>
|
32
|
+
</p>
|
33
|
+
</div>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<div class="gricer-stat">
|
2
|
+
<div id="gricer-header">
|
3
|
+
<span class="path"></span>
|
4
|
+
<span class="dates">
|
5
|
+
<%= form_tag do -%>
|
6
|
+
<%= text_field_tag :from, @stat_from, id: 'gricer-from-field' -%>
|
7
|
+
-
|
8
|
+
<%= text_field_tag :thru, @stat_thru, id: 'gricer-thru-field' %>
|
9
|
+
<% end -%>
|
10
|
+
</span>
|
11
|
+
</div>
|
12
|
+
<div id="gricer-menu">
|
13
|
+
<%= render 'menu', items: ::Gricer.config.admin_menu %>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<div id="gricer-container"></div>
|
17
|
+
|
18
|
+
<%= javascript_include_tag :gricer_backend_jquery %>
|
19
|
+
</div>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
post 'gricer_capture/:id' => 'gricer/capture#index', as: :gricer_capture
|
3
|
+
|
4
|
+
scope ::Gricer.config.admin_prefix do
|
5
|
+
root to: "gricer/dashboard#index", as: :gricer_root
|
6
|
+
post 'overview' => "gricer/dashboard#overview", as: :gricer_overview
|
7
|
+
|
8
|
+
scope 'sessions' do
|
9
|
+
[
|
10
|
+
'agent.name', 'agent.os', 'agent.full_version', 'agent.major_version', 'agent.engine_name', 'agent.engine_version',
|
11
|
+
'javascript', 'java', 'silverlight_version', 'silverlight_major_version', 'flash_version', 'flash_major_version',
|
12
|
+
'country', 'city', 'domain', 'screen_size', 'screen_width', 'screen_height', 'screen_depth',
|
13
|
+
'requested_locale_major', 'requested_locale_minor', 'requested_locale',
|
14
|
+
].each do |field|
|
15
|
+
name = field.gsub('.', '_')
|
16
|
+
get "#{name}_process" => "gricer/sessions#process_stats", field: field, as: "gricer_sessions_#{name}_process"
|
17
|
+
get "#{name}_spread" => "gricer/sessions#spread_stats", field: field, as: "gricer_sessions_#{name}_spread"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
scope 'requests' do
|
22
|
+
[
|
23
|
+
'agent.name', 'agent.os', 'agent.full_version', 'agent.major_version', 'agent.engine_name', 'agent.engine_version',
|
24
|
+
'host', 'path', 'method', 'protocol', 'entry_path',
|
25
|
+
'referer_protocol', 'referer_host', 'referer_path', 'referer_params',
|
26
|
+
'search_engine', 'search_query',
|
27
|
+
].each do |field|
|
28
|
+
name = field.gsub('.', '_')
|
29
|
+
get "#{name}_process" => "gricer/requests#process_stats", field: field, as: "gricer_requests_#{name}_process"
|
30
|
+
get "#{name}_spread" => "gricer/requests#spread_stats", field: field, as: "gricer_requests_#{name}_spread"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Gricer::Engine.routes.draw do
|
37
|
+
# root to: "dashboard#index"
|
38
|
+
#
|
39
|
+
# scope 'sessions' do
|
40
|
+
# [
|
41
|
+
# 'agent.name', 'agent.os', 'agent.full_version', 'agent.major_version', 'agent.engine_name', 'agent.engine_version',
|
42
|
+
# 'javascript', 'java', 'silverlight_version', 'silverlight_major_version', 'flash_version', 'flash_major_version',
|
43
|
+
# 'country', 'city', 'domain', 'screen_size', 'screen_width', 'screen_height', 'screen_depth',
|
44
|
+
# 'requested_major_locale', 'requested_minor_locale', 'requested_locale',
|
45
|
+
# ].each do |field|
|
46
|
+
# name = field.gsub('.', '_')
|
47
|
+
# get "#{name}_process" => "sessions#process_stats", field: field, as: "gricer_session_#{name}_process"
|
48
|
+
# get "#{name}_spread" => "sessions#spread_stats", field: field, as: "gricer_session_#{name}_spread"
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
# end
|
data/lib/gricer.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "gricer/config"
|
2
|
+
require "gricer/engine"
|
3
|
+
require "gricer/localization"
|
4
|
+
|
5
|
+
require 'gricer/action_controller/base'
|
6
|
+
require 'gricer/action_controller/track'
|
7
|
+
|
8
|
+
require 'gricer/active_model/statistics'
|
9
|
+
|
10
|
+
# Gricer is a web analytics gem for Rails 3.1 and beyond
|
11
|
+
module Gricer
|
12
|
+
class << self
|
13
|
+
# To access the actual configuration of your Gricer, you can call this function.
|
14
|
+
#
|
15
|
+
# An example would be <tt>Gricer.config.table_name_prefix = 'stats_'</tt>
|
16
|
+
#
|
17
|
+
# See Gricer::Config for configuration options.
|
18
|
+
#
|
19
|
+
# @return [Gricer::Config] The actual configuration instance of Gricer
|
20
|
+
# @see Gricer::Config
|
21
|
+
def config
|
22
|
+
@config ||= Config.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# To initialize Gricer it is handy to give it a block of options.
|
26
|
+
#
|
27
|
+
# See Gricer::Config for configuration options.
|
28
|
+
#
|
29
|
+
# @yield (config) The actual configuration instance of Gricer
|
30
|
+
# @return [Gricer::Config] The actual configuration instance of Gricer
|
31
|
+
# @see Gricer::Config
|
32
|
+
def configure(&block)
|
33
|
+
config.configure(&block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Gricer
|
2
|
+
# Gricer's ActionController enhancements
|
3
|
+
module ActionController
|
4
|
+
# Gricer's ActionController base enhancements
|
5
|
+
module Base
|
6
|
+
|
7
|
+
# Include the helper functions into controllers.
|
8
|
+
def self.included(base)
|
9
|
+
base.module_eval do
|
10
|
+
helper_attr :gricer_user_id
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# This function is a stub for the mechanism to include the current
|
15
|
+
# users id into the statistics of gricer.
|
16
|
+
# @example The most common case would be to pass the current_user's id. So this is the code you should add to your appliction_controller
|
17
|
+
# def gricer_user_id
|
18
|
+
# current_user.try(:id)
|
19
|
+
# end
|
20
|
+
# @return [Integer]
|
21
|
+
def gricer_user_id
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ActionController::Base.send :include, Gricer::ActionController::Base
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Gricer
|
2
|
+
# Around-Filter for tracking requests in Gricer
|
3
|
+
class TrackRequestFilter
|
4
|
+
# Around-Filter for tracking requests in Gricer
|
5
|
+
# @param controller The controller from which this Filter was included.
|
6
|
+
# @yield The controller's code block
|
7
|
+
def self.filter(controller, &block)
|
8
|
+
if controller.controller_path =~ /^gricer\// or controller.request.path =~ ::Gricer.config.exclude_paths
|
9
|
+
Rails.logger.debug "Gricer Track Request: Do not track '#{controller.controller_path}##{controller.action_name}' by config"
|
10
|
+
block.call
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
14
|
+
status = nil
|
15
|
+
|
16
|
+
options = {
|
17
|
+
request: controller.request,
|
18
|
+
controller: controller.controller_path,
|
19
|
+
action: controller.action_name,
|
20
|
+
params: controller.params,
|
21
|
+
session_id: controller.session[:gricer_session],
|
22
|
+
locale: I18n.locale
|
23
|
+
}
|
24
|
+
|
25
|
+
if controller.gricer_user_id
|
26
|
+
options[:user_id] = controller.gricer_user_id
|
27
|
+
end
|
28
|
+
|
29
|
+
options.keys.each do |key|
|
30
|
+
Rails.logger.debug key
|
31
|
+
end
|
32
|
+
|
33
|
+
gricer_request = ::Gricer::Request.create options
|
34
|
+
controller.gricer_request = gricer_request
|
35
|
+
controller.session[:gricer_session] = gricer_request.session_id
|
36
|
+
|
37
|
+
begin
|
38
|
+
benchmark = Benchmark.measure(&block)
|
39
|
+
|
40
|
+
gricer_request.update_attributes(
|
41
|
+
status_code: controller.response.status,
|
42
|
+
content_type: controller.response.content_type,
|
43
|
+
body_size: controller.response.body.size,
|
44
|
+
system_time: (benchmark.cstime*1000).to_i,
|
45
|
+
user_time: (benchmark.cutime*1000).to_i,
|
46
|
+
total_time: (benchmark.total*1000).to_i,
|
47
|
+
real_time: (benchmark.real*1000).to_i
|
48
|
+
)
|
49
|
+
rescue
|
50
|
+
gricer_request.update_attributes(
|
51
|
+
status_code: 500,
|
52
|
+
content_type: controller.response.content_type,
|
53
|
+
body_size: controller.response.body.size
|
54
|
+
)
|
55
|
+
raise
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Helper Method to include Javascript code to capture extra values like screen size
|
61
|
+
module TrackHelper
|
62
|
+
# Include Gricer's Javascript code to track values like screen size.
|
63
|
+
#
|
64
|
+
# You should include this at the end of your layout file. For pages matching the
|
65
|
+
# Gricer::Config.exclude_paths expression, nothing will be added to your page.
|
66
|
+
#
|
67
|
+
# @example For html.erb add at the end of your layout file:
|
68
|
+
# <html>
|
69
|
+
# <head>[...]</head>
|
70
|
+
# <body>
|
71
|
+
# [...]
|
72
|
+
# <%= gricer_track_tag %>
|
73
|
+
# </body>
|
74
|
+
# </html>
|
75
|
+
#
|
76
|
+
# @example For html.haml add at the end of your layout file:
|
77
|
+
# %html
|
78
|
+
# %head
|
79
|
+
# [...]
|
80
|
+
# %body
|
81
|
+
# [...]
|
82
|
+
# = gricer_track_tag
|
83
|
+
|
84
|
+
def gricer_track_tag
|
85
|
+
if gricer_request and defined?(gricer_capture_path)
|
86
|
+
content_tag :script, "jQuery(function($) {$.post('#{gricer_capture_path(gricer_request.id)}', Gricer.prepareValues());});", type: 'text/javascript'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
module ActionController
|
92
|
+
# Gricer's Tracker module for ActionController
|
93
|
+
#
|
94
|
+
# To include the Tracker module into ActionController add
|
95
|
+
# gricer_track_requests to your ApplicationController or
|
96
|
+
# to any Controller you want to track with Gricer.
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# class ApplicationController < ActionController::Base
|
100
|
+
# protect_from_forgery
|
101
|
+
# gricer_track_requests
|
102
|
+
# [...]
|
103
|
+
# end
|
104
|
+
|
105
|
+
module Tracker
|
106
|
+
# Include the helper functions and around_filter into controllers.
|
107
|
+
def self.included(base)
|
108
|
+
base.append_around_filter TrackRequestFilter
|
109
|
+
base.helper TrackHelper
|
110
|
+
base.helper_method :gricer_request
|
111
|
+
end
|
112
|
+
|
113
|
+
# Set the actual gricer request instance.
|
114
|
+
# @param gricer_request [Gricer::Request] The gricer request to be set as actual request instance.
|
115
|
+
def gricer_request=(gricer_request)
|
116
|
+
@gricer_request = gricer_request
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get the actual gricer request instance.
|
120
|
+
# @return [Gricer::Request]
|
121
|
+
def gricer_request
|
122
|
+
@gricer_request
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class ActionController::Base
|
129
|
+
def self.gricer_track_requests(options = {})
|
130
|
+
include Gricer::ActionController::Tracker
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module Gricer
|
2
|
+
# Gricer's ActiveModel enhancements
|
3
|
+
module ActiveModel
|
4
|
+
# Gricer's statistics enhancements for ActiveModel
|
5
|
+
#
|
6
|
+
# To add statistics to an ActiveRecord just include the module:
|
7
|
+
# class SomeDataModel < ::ActiveRecord::Base
|
8
|
+
# include ActiveModel::Statistics
|
9
|
+
# [...]
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# This module provides two major enhancements:
|
13
|
+
#
|
14
|
+
# == Extendend attribute names
|
15
|
+
#
|
16
|
+
# You can use relation attributes by using a dot in your attribute name.
|
17
|
+
#
|
18
|
+
# *Example:*
|
19
|
+
#
|
20
|
+
# For getting the name of the attribute name of Agent associated to the Request:
|
21
|
+
# Gricer::Request.human_attributes('agent.name')
|
22
|
+
#
|
23
|
+
# == Statistics functions and filters
|
24
|
+
#
|
25
|
+
# Methods for filtering, grouping, and counting records
|
26
|
+
module Statistics
|
27
|
+
# Extend the ActiveModel with the statistics class methods.
|
28
|
+
# @see ClassMethods
|
29
|
+
def self.included(base)
|
30
|
+
base.extend ClassMethods
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gricer's statistics enhancements for ActiveModel
|
34
|
+
#
|
35
|
+
# == Extended attribute names
|
36
|
+
# You can use relation attributes by using a dot in your attribute name.
|
37
|
+
#
|
38
|
+
# @example For getting the name of the attribute name of Agent associated to the Request:
|
39
|
+
# Gricer::Request.human_attributes('agent.name')
|
40
|
+
module ClassMethods
|
41
|
+
# Filter records for the time between from and thru
|
42
|
+
# @param from [Date, Time] Only get records on or after this point of time
|
43
|
+
# @param thru [Date, Time] Only get records before this point of time
|
44
|
+
# @return [ActiveRecord::Relation]
|
45
|
+
def between(from, thru)
|
46
|
+
#self.where(self.table_name => {:created_at.gte => from, :created_at.lt => thru})
|
47
|
+
self.where("\"#{table_name}\".\"created_at\" >= ? AND \"#{table_name}\".\"created_at\" < ?", from, thru)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Filter records for the dates between from and thru
|
51
|
+
# @param from [Date] Only get records on or after this date
|
52
|
+
# @param thru [Date] Only get records on or before this date
|
53
|
+
# @return [ActiveRecord::Relation]
|
54
|
+
def between_dates(from, thru)
|
55
|
+
self.between(from.to_date.to_time, thru.to_date.to_time+1.day)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Group records by attribute.
|
59
|
+
#
|
60
|
+
# @param attribute [String, Symbol] Attribute to group the records for. You can use gricers extended attribute names.
|
61
|
+
# @return [ActiveRecord::Relation]
|
62
|
+
def grouped_by(attribute)
|
63
|
+
parts = attribute.to_s.split('.')
|
64
|
+
if parts[1].blank?
|
65
|
+
self.group(attribute)
|
66
|
+
.select(attribute)
|
67
|
+
else
|
68
|
+
if association = self.reflect_on_association(parts[0].to_sym)
|
69
|
+
self.includes(association.name)
|
70
|
+
.group("\"#{association.table_name}\".\"#{parts[1]}\"")
|
71
|
+
.select("\"#{association.table_name}\".\"#{parts[1]}\"")
|
72
|
+
else
|
73
|
+
raise "Association '#{parts[0]}' not found on #{self.name}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Count records by attribute.
|
79
|
+
#
|
80
|
+
# @param attribute [String, Symbol] Attribute name to count for. You can use gricers extended attribute names.
|
81
|
+
# @return [ActiveRecord::Relation]
|
82
|
+
def count_by(attribute)
|
83
|
+
self.grouped_by(attribute).count(:id).sort{ |a,b| b[1] <=> a[1] }
|
84
|
+
end
|
85
|
+
|
86
|
+
# Filter records by attribute's value.
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# some_relation.filter('agent.name', 'Internet Explorer').filter('agent.os', 'Windows')
|
90
|
+
# @param attribute [String, Symbol] Attribute name to filter. You can use gricers extended attribute names.
|
91
|
+
# @param value Attribute value to filter.
|
92
|
+
# @return [ActiveRecord::Relation]
|
93
|
+
|
94
|
+
def filter_by(attribute, value)
|
95
|
+
return self if attribute.blank?
|
96
|
+
|
97
|
+
Rails.logger.debug "Attr: #{attribute}, Value: #{value}"
|
98
|
+
|
99
|
+
parts = attribute.to_s.split('.')
|
100
|
+
if parts[1].blank?
|
101
|
+
self.where(attribute => value)
|
102
|
+
else
|
103
|
+
if association = self.reflect_on_association(parts[0].to_sym)
|
104
|
+
self.includes(association.name)
|
105
|
+
.where(association.table_name => {parts[1] => value})
|
106
|
+
else
|
107
|
+
raise "Association '#{parts[0]}' not found on #{self.name}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Extends ActiveModel::Translation#human_attribute_name to use Gricer's extended attribute names.
|
113
|
+
#
|
114
|
+
# @param attribute [String, Symbol] Attribute name to get human name for. You can use gricers extended attribute names.
|
115
|
+
# @param options [Hash] See ActiveModel::Translation for possible options.
|
116
|
+
# @return [String]
|
117
|
+
def human_attribute_name(attribute, options = {})
|
118
|
+
parts = attribute.to_s.split('.')
|
119
|
+
if parts[1].blank?
|
120
|
+
super attribute, options
|
121
|
+
else
|
122
|
+
if association = self.reflect_on_association(parts[0].to_sym)
|
123
|
+
association.active_record.human_attribute_name parts[1], options
|
124
|
+
else
|
125
|
+
parts[1].to_s.humanize
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
# Return hash for values of an attribute within the given time
|
132
|
+
#
|
133
|
+
#
|
134
|
+
# @example Get agent.name statistics for 2011-07-05 08:00 until 2011-07-06 08:00
|
135
|
+
# Gricer::Request.stat('agent.name', '2011-07-05 08:00', '2011-07-06 08:00')
|
136
|
+
# @example Get agent.engine_version statistics for agents with engine_name = 'Presto' and values between 2011-07-05 08:00 and last hour with values in 15 minutes steps
|
137
|
+
# Gricer::Request.where('gricer_agents.engine_name = ?', 'Presto').stat('agent.engine_version', '2011-07-05 08:00', Time.now - 1.hour, 15.minutes)
|
138
|
+
#
|
139
|
+
# @param attribute [String, Symbol] Attribute name to get data for. You can use gricers extended attribute names.
|
140
|
+
# @param from [Date, Time] Only get records on or after this point of time
|
141
|
+
# @param thru [Date, Time] Only get records before this point of time
|
142
|
+
# @param step [Integer] Time interval for grouping values
|
143
|
+
# @return [Hash]
|
144
|
+
def stat(attribute, from, thru, step = 1.hour)
|
145
|
+
query = self.grouped_by(attribute)
|
146
|
+
|
147
|
+
from = from.to_date.to_time
|
148
|
+
thru = thru.to_date.to_time+1.day
|
149
|
+
|
150
|
+
now = from
|
151
|
+
|
152
|
+
stats = {}
|
153
|
+
|
154
|
+
while now < thru do
|
155
|
+
self.between(now, now + step).count_by(attribute).each do |value|
|
156
|
+
stats[value[0]] ||= []
|
157
|
+
stats[value[0]] << [now.to_i*1000, value[1]]
|
158
|
+
end
|
159
|
+
now += step
|
160
|
+
end
|
161
|
+
|
162
|
+
return stats
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|