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,240 @@
|
|
1
|
+
@import 'helpers/css3';
|
2
|
+
|
3
|
+
.gricer-stat {
|
4
|
+
position: absolute;
|
5
|
+
top: 0;
|
6
|
+
bottom: 0;
|
7
|
+
width: 100%;
|
8
|
+
overflow: none;
|
9
|
+
font-size: 11px;
|
10
|
+
line-height: 15px;
|
11
|
+
font-family: 'Lucida Grande', 'Arial', 'Helvetica', 'Sans-Serif';
|
12
|
+
|
13
|
+
#gricer-header {
|
14
|
+
background: #000;
|
15
|
+
color: #000;
|
16
|
+
line-height: 20px;
|
17
|
+
height: 20px;
|
18
|
+
background: #eee;
|
19
|
+
@include gradient(#eee,#ccc);
|
20
|
+
|
21
|
+
.path {
|
22
|
+
a {
|
23
|
+
display: block;
|
24
|
+
float: left;
|
25
|
+
color: #000;
|
26
|
+
background: image-url("gricer/fluid/breadcrumb.png") right top no-repeat;
|
27
|
+
height: 20px;
|
28
|
+
line-height: 20px;
|
29
|
+
padding: 0 15px 0 8px;
|
30
|
+
text-decoration: none;
|
31
|
+
}
|
32
|
+
|
33
|
+
a:last-child {
|
34
|
+
font-weight: bold;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
.dates {
|
39
|
+
padding: 0 7px;
|
40
|
+
float: right;
|
41
|
+
input {
|
42
|
+
width: 8em;
|
43
|
+
height: 11px;
|
44
|
+
padding: 2px;
|
45
|
+
border: none;
|
46
|
+
background: transparent;
|
47
|
+
}
|
48
|
+
#gricer-from-field {
|
49
|
+
text-align: right;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
#gricer-menu {
|
55
|
+
position: absolute;
|
56
|
+
float: left;
|
57
|
+
width: 182px;
|
58
|
+
padding: 4px 0;
|
59
|
+
background: #dfe4eb;
|
60
|
+
border-right: 1px solid #b4b4b4;
|
61
|
+
top: 20px;
|
62
|
+
|
63
|
+
bottom: 0;
|
64
|
+
overflow: auto;
|
65
|
+
|
66
|
+
a, span {
|
67
|
+
display: block;
|
68
|
+
text-decoration: none;
|
69
|
+
color: #000;
|
70
|
+
border-top: 1px solid transparent;
|
71
|
+
padding: 2px 8px;
|
72
|
+
&.active {
|
73
|
+
border-top: 1px solid #a3b1cc;
|
74
|
+
background: #94a6c5;
|
75
|
+
@include gradient(#b0bed7, #8195b8);
|
76
|
+
color: #fff;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
span {
|
81
|
+
color: #999;
|
82
|
+
font-weight: bold;
|
83
|
+
}
|
84
|
+
|
85
|
+
div a {
|
86
|
+
padding-left: 16px;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
#gricer-container
|
91
|
+
{
|
92
|
+
position: absolute;
|
93
|
+
float: left;
|
94
|
+
left: 183px;
|
95
|
+
top: 20px;
|
96
|
+
right: 0;
|
97
|
+
bottom: 0;
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
#gricer-container {
|
102
|
+
|
103
|
+
.overview {
|
104
|
+
position: absolute;
|
105
|
+
top: 0;
|
106
|
+
bottom: 0;
|
107
|
+
width: 100%;
|
108
|
+
overflow: auto;
|
109
|
+
padding: 4px 8px;
|
110
|
+
font-size: 30px;
|
111
|
+
line-height: 45px;
|
112
|
+
}
|
113
|
+
|
114
|
+
.flot-chart {
|
115
|
+
position: absolute;
|
116
|
+
background: #666f83;
|
117
|
+
color: #999;
|
118
|
+
top: 0;
|
119
|
+
left: 0;
|
120
|
+
right: 0;
|
121
|
+
padding: 0 2.5%;
|
122
|
+
height: 250px;
|
123
|
+
#flot-line-chart, #flot-pie-chart {
|
124
|
+
width: 100%;
|
125
|
+
height: 250px;
|
126
|
+
}
|
127
|
+
|
128
|
+
}
|
129
|
+
|
130
|
+
.type-selector {
|
131
|
+
position: absolute;
|
132
|
+
right: 4px;
|
133
|
+
top: 4px;
|
134
|
+
|
135
|
+
span, a {
|
136
|
+
padding: 2px 4px;
|
137
|
+
background: #ccc;
|
138
|
+
@include gradient(#ddd, #bbb);
|
139
|
+
border-right: 1px solid #b4b4b4;
|
140
|
+
color: #000;
|
141
|
+
text-decoration: none;
|
142
|
+
}
|
143
|
+
|
144
|
+
span {
|
145
|
+
background: #666;
|
146
|
+
@include gradient(#555, #777);
|
147
|
+
color: #fff;
|
148
|
+
}
|
149
|
+
|
150
|
+
span:first-child,
|
151
|
+
a:first-child {
|
152
|
+
@include border-radius(9px 0 0 9px);
|
153
|
+
padding-left: 9px;
|
154
|
+
}
|
155
|
+
|
156
|
+
span:last-child,
|
157
|
+
a:last-child {
|
158
|
+
@include border-radius(0 9px 9px 0);
|
159
|
+
border-right: none;
|
160
|
+
padding-right: 9px;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
.data {
|
165
|
+
position: absolute;
|
166
|
+
top: 250px;
|
167
|
+
bottom: 0;
|
168
|
+
width: 100%;
|
169
|
+
overflow: auto;
|
170
|
+
}
|
171
|
+
table {
|
172
|
+
width: 100%;
|
173
|
+
padding: 0;
|
174
|
+
border-spacing: 0;
|
175
|
+
empty-cells: show;
|
176
|
+
|
177
|
+
th, td {
|
178
|
+
width: auto;
|
179
|
+
padding: 2px 4px;
|
180
|
+
font-size: 11px;
|
181
|
+
|
182
|
+
a {
|
183
|
+
color: #009;
|
184
|
+
text-decoration: none;
|
185
|
+
}
|
186
|
+
|
187
|
+
.badge {
|
188
|
+
float: left;
|
189
|
+
display: block;
|
190
|
+
@include border-radius(5px);
|
191
|
+
margin: 3px;
|
192
|
+
width: 10px;
|
193
|
+
height: 10px;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
tr:nth-child(even) {
|
198
|
+
th, td {
|
199
|
+
background-color: #f3f5fa;
|
200
|
+
white-space: nowrap;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
|
204
|
+
tr:first-child {
|
205
|
+
th {
|
206
|
+
background: #eee;
|
207
|
+
@include gradient(#ccc,#eee);
|
208
|
+
border-bottom: 1px solid #b4b4b4;
|
209
|
+
border-right: 1px solid #b4b4b4;
|
210
|
+
overflow: hidden;
|
211
|
+
white-space: nowrap;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
th.number,
|
216
|
+
td.number {
|
217
|
+
text-align: right;
|
218
|
+
}
|
219
|
+
|
220
|
+
th.boolean,
|
221
|
+
td.boolean {
|
222
|
+
max-width: 30px;
|
223
|
+
}
|
224
|
+
|
225
|
+
td.boolean {
|
226
|
+
text-align: center;
|
227
|
+
}
|
228
|
+
|
229
|
+
&.process {
|
230
|
+
tr:nth-child(1) {
|
231
|
+
th {
|
232
|
+
text-align: center;
|
233
|
+
font-size: 9px;
|
234
|
+
lin-height: 11px;
|
235
|
+
}
|
236
|
+
}
|
237
|
+
}
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
@mixin border-radius($radius) {
|
2
|
+
-webkit-border-radius: $radius;
|
3
|
+
-moz-border-radius: $radius;
|
4
|
+
-o-border-radius: $radius;
|
5
|
+
-ms-border-radius: $radius;
|
6
|
+
-khtml-border-radius: $radius;
|
7
|
+
border-radius: $radius;
|
8
|
+
}
|
9
|
+
|
10
|
+
@mixin gradient($from, $to) {
|
11
|
+
background-image: -webkit-gradient(linear, left top, left bottom, from($from), to($to));
|
12
|
+
background-image: -moz-linear-gradient($from, $to);
|
13
|
+
background-image: linear-gradient($from, $to);
|
14
|
+
}
|
15
|
+
|
16
|
+
@mixin rotate($degree: -90deg) {
|
17
|
+
-moz-transform:rotate($degree);
|
18
|
+
-webkit-transform:rotate($degree);
|
19
|
+
-o-transform:rotate($degree);
|
20
|
+
transform:rotate($degree);
|
21
|
+
}
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Gricer
|
2
|
+
# This is the base controller which is used by Gricer's basic statistics controllers
|
3
|
+
#
|
4
|
+
# You can use this to make your own statistics controllers from a scaffold.
|
5
|
+
class BaseController < ::ApplicationController
|
6
|
+
before_filter :guess_from_thru
|
7
|
+
helper BaseHelper
|
8
|
+
|
9
|
+
layout ::Gricer.config.admin_layout if ::Gricer.config.admin_layout
|
10
|
+
|
11
|
+
# This action generates a JSON for a process statistics.
|
12
|
+
def process_stats
|
13
|
+
@items = basic_collection
|
14
|
+
|
15
|
+
handle_special_fields
|
16
|
+
|
17
|
+
data = {
|
18
|
+
alternatives: [
|
19
|
+
{
|
20
|
+
type: 'spread',
|
21
|
+
uri: url_for(action: "spread_stats", field: params[:field], filters: params[:filters], only_path: true)
|
22
|
+
},
|
23
|
+
{
|
24
|
+
type: 'process'
|
25
|
+
}
|
26
|
+
],
|
27
|
+
from: @stat_from.to_time.utc.to_i * 1000,
|
28
|
+
thru: @stat_thru.to_time.utc.to_i * 1000,
|
29
|
+
step: @stat_step.to_i * 1000,
|
30
|
+
data: @items.stat(params[:field], @stat_from, @stat_thru, @stat_step)
|
31
|
+
}
|
32
|
+
|
33
|
+
if further_details.keys.include? params[:field]
|
34
|
+
filters = (params[:filters] || {})
|
35
|
+
filters[params[:field]] = '%{self}'
|
36
|
+
|
37
|
+
data[:detail_uri] = url_for(action: "process_stats", field: further_details[params[:field]], filters: filters, only_path: true)
|
38
|
+
end
|
39
|
+
|
40
|
+
render json: data
|
41
|
+
end
|
42
|
+
|
43
|
+
# This action generates a JSON for a spread statistics.
|
44
|
+
def spread_stats
|
45
|
+
@items = basic_collection.between_dates(@stat_from, @stat_thru)
|
46
|
+
|
47
|
+
handle_special_fields
|
48
|
+
|
49
|
+
data = {
|
50
|
+
alternatives: [
|
51
|
+
{
|
52
|
+
type: 'spread'
|
53
|
+
},
|
54
|
+
{
|
55
|
+
type: 'process',
|
56
|
+
uri: url_for(action: "process_stats", field: params[:field], filters: params[:filters], only_path: true)
|
57
|
+
}
|
58
|
+
],
|
59
|
+
from: @stat_from.to_time.utc.to_i * 1000,
|
60
|
+
thru: @stat_thru.to_time.utc.to_i * 1000,
|
61
|
+
total: @items.count(:id),
|
62
|
+
data: @items.count_by(params[:field])
|
63
|
+
}
|
64
|
+
|
65
|
+
if further_details.keys.include? params[:field]
|
66
|
+
filters = (params[:filters] || {})
|
67
|
+
filters[params[:field]] = '%{self}'
|
68
|
+
|
69
|
+
data[:detail_uri] = url_for(action: "spread_stats", field: further_details[params[:field]], filters: filters, only_path: true)
|
70
|
+
end
|
71
|
+
|
72
|
+
render json: data
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
# @abstract
|
77
|
+
# Define which is the basic collection to be processed by the controller.
|
78
|
+
# This value has to be overwritten to use the process_stats or spread_stats actions.
|
79
|
+
def basic_collection
|
80
|
+
raise 'basic_collection must be defined'
|
81
|
+
end
|
82
|
+
|
83
|
+
# Define how to handle special fields
|
84
|
+
def handle_special_fields
|
85
|
+
if params[:filters]
|
86
|
+
params[:filters].each do |filter_attr, filter_value|
|
87
|
+
@items = @items.filter_by(filter_attr, filter_value)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Define how to handle further details
|
93
|
+
def further_details
|
94
|
+
{}
|
95
|
+
end
|
96
|
+
|
97
|
+
# Guess for which time range to display statistics
|
98
|
+
def guess_from_thru
|
99
|
+
begin
|
100
|
+
@stat_thru = Time.parse(params[:thru]).to_date
|
101
|
+
rescue
|
102
|
+
end
|
103
|
+
|
104
|
+
begin
|
105
|
+
@stat_from = Time.parse(params[:from]).to_date
|
106
|
+
rescue
|
107
|
+
end
|
108
|
+
|
109
|
+
if @stat_from.nil?
|
110
|
+
if @stat_thru.nil?
|
111
|
+
@stat_thru = Time.now.localtime.to_date - 1.day
|
112
|
+
end
|
113
|
+
@stat_from = @stat_thru - 1.week + 1.day
|
114
|
+
else
|
115
|
+
if @stat_thru.nil?
|
116
|
+
@stat_thru = @stat_from + 1.week - 1.day
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
@stat_step = 1.day
|
121
|
+
|
122
|
+
duration = @stat_thru - @stat_from
|
123
|
+
|
124
|
+
if duration < 90
|
125
|
+
@stat_step = 12.hours
|
126
|
+
end
|
127
|
+
|
128
|
+
if duration < 30
|
129
|
+
@stat_step = 6.hour
|
130
|
+
end
|
131
|
+
|
132
|
+
if duration < 10
|
133
|
+
@stat_step = 1.hour
|
134
|
+
end
|
135
|
+
|
136
|
+
#if @stat_thru - @stat_from > 12.month
|
137
|
+
# @stat_step = 4.week
|
138
|
+
#end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Gricer
|
2
|
+
# This is the controller to capture additional values from the Javascript track tag.
|
3
|
+
#
|
4
|
+
# @see Gricer::TrackHelper#gricer_track_tag
|
5
|
+
class CaptureController < ::ApplicationController
|
6
|
+
# This action stores the data submitted by the Javascript.
|
7
|
+
def index
|
8
|
+
gricer_request = Request.find_by_id(params[:id])
|
9
|
+
gricer_session = Session.find_by_id(session[:gricer_session])
|
10
|
+
|
11
|
+
if gricer_session
|
12
|
+
gricer_session.javascript = true
|
13
|
+
gricer_session.java = params[:j]
|
14
|
+
gricer_session.flash_version = params[:f] unless params[:f] == 'false'
|
15
|
+
gricer_session.silverlight_version = params[:sl] unless params[:sl] == 'false'
|
16
|
+
gricer_session.screen_width = params[:sx]
|
17
|
+
gricer_session.screen_height = params[:sy]
|
18
|
+
gricer_session.screen_size = "#{params[:sx]}x#{params[:sy]}" unless params[:sx].blank? or params[:sy].blank?
|
19
|
+
gricer_session.screen_depth = params[:sd]
|
20
|
+
gricer_session.save
|
21
|
+
|
22
|
+
if gricer_request and gricer_request.session == gricer_session
|
23
|
+
|
24
|
+
gricer_request.javascript = true
|
25
|
+
gricer_request.window_width = params[:wx]
|
26
|
+
gricer_request.window_height = params[:wy]
|
27
|
+
|
28
|
+
if gricer_request.save
|
29
|
+
render text: 'ok'
|
30
|
+
else
|
31
|
+
render text: 'session only', status: 500
|
32
|
+
end
|
33
|
+
return
|
34
|
+
else
|
35
|
+
render text: 'session only'
|
36
|
+
return
|
37
|
+
end
|
38
|
+
end
|
39
|
+
render text: 'failed', status: 500
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Gricer
|
2
|
+
# This controller contains the dashboard for the administration view
|
3
|
+
class DashboardController < BaseController
|
4
|
+
# This action renders the frame for the statistics tool
|
5
|
+
def index
|
6
|
+
@sessions = Session.browsers.between_dates(@stat_from, @stat_thru)
|
7
|
+
@requests = Request.browsers.between_dates(@stat_from, @stat_thru)
|
8
|
+
end
|
9
|
+
|
10
|
+
# This action renderes the overview of some data in the statistics tool
|
11
|
+
def overview
|
12
|
+
@sessions = Session.browsers.between_dates(@stat_from, @stat_thru)
|
13
|
+
@requests = Request.browsers.between_dates(@stat_from, @stat_thru)
|
14
|
+
|
15
|
+
render partial: 'overview.html', locals: {sessions: @sessions, requests: @requests}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|