gricer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|