rack-reqorder 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -3
- data/README.md +9 -1
- data/lib/rack/reqorder.rb +12 -17
- data/lib/rack/reqorder/logger.rb +38 -16
- data/lib/rack/reqorder/models/app_fault.rb +5 -0
- data/lib/rack/reqorder/models/route_path.rb +6 -26
- data/lib/rack/reqorder/models/statistic.rb +5 -1
- data/lib/rack/reqorder/monitor.rb +80 -10
- data/lib/rack/reqorder/monitor/entities.rb +76 -1
- data/lib/rack/reqorder/monitor/helpers.rb +92 -0
- data/lib/rack/reqorder/route_recognizers.rb +156 -0
- data/lib/rack/reqorder/tasks/routes.rake +1 -1
- data/lib/rack/reqorder/tasks/test_database.rake +29 -0
- data/lib/rack/reqorder/version.rb +1 -1
- data/rack-reqorder.gemspec +8 -4
- metadata +69 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92a69c99b0738479b0b998e1a7f7c5d3f3051f46
|
4
|
+
data.tar.gz: 7e032e5347593d459db3e183dd1b1cb653d91b7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b80ff10e5dfb1ff79ae7f5233b495f62f2e63374528e31742614e4b1f34b2501c4a44399c8d7655e0e65cc9b2efa845040b2f302c49d2a621290328b0889a08
|
7
|
+
data.tar.gz: f732af69470fb3123ada1da63fb932d68863832c53901fbe2ef98441a3d36256bb90bf49a20ff7fa60c0b00772665ee9ffc3ef993c33bb1fb967a3ff59cce71d
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -27,7 +27,13 @@ Or install it yourself as:
|
|
27
27
|
$ gem install rack-reqorder
|
28
28
|
|
29
29
|
## Usage
|
30
|
-
|
30
|
+
You first need to initialize mongoid/mongodb by running:
|
31
|
+
|
32
|
+
```bash
|
33
|
+
bundle exec rails g mongoid:config
|
34
|
+
```
|
35
|
+
|
36
|
+
Then just add it on the middleware pipeline and initialize it.
|
31
37
|
|
32
38
|
For instance, in Rails, in an initializer add:
|
33
39
|
|
@@ -51,6 +57,8 @@ end
|
|
51
57
|
Please note that you can configure origins and resource depending on how you
|
52
58
|
mount the rack-monitor engine and where you deploy your front-end.
|
53
59
|
|
60
|
+
For viewing your statistics please check [rack-reqorder-monitor](https://github.com/kollegorna/rack-reqorder-monitor)
|
61
|
+
|
54
62
|
## Development
|
55
63
|
|
56
64
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/rack/reqorder.rb
CHANGED
@@ -3,9 +3,14 @@ require 'active_support/inflector'
|
|
3
3
|
require 'mongoid'
|
4
4
|
require 'kaminari'
|
5
5
|
require 'kaminari/models/mongoid_extension'
|
6
|
+
require 'rack/reqorder/route_recognizers'
|
6
7
|
|
7
8
|
module Rack
|
8
9
|
module Reqorder
|
10
|
+
extend Rack::Reqorder::GrapeRecognizer
|
11
|
+
extend Rack::Reqorder::SinatraRecognizer
|
12
|
+
extend Rack::Reqorder::RailsRecognizer
|
13
|
+
|
9
14
|
class << self
|
10
15
|
attr_accessor :configuration
|
11
16
|
end
|
@@ -24,24 +29,9 @@ module Rack
|
|
24
29
|
)
|
25
30
|
end
|
26
31
|
|
27
|
-
def self.paths
|
28
|
-
return @paths unless @paths.blank?
|
29
|
-
@paths = {}
|
30
|
-
Rails.application.routes.routes.routes.each do |route|
|
31
|
-
@paths[route.defaults] = route.path.spec.left.to_s
|
32
|
-
end
|
33
|
-
|
34
|
-
return @paths
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.recognise_path(path_uri, options = {})
|
38
|
-
res = Rack::Reqorder.paths[Rails.application.routes.recognize_path(path_uri, options)
|
39
|
-
.select{|key, value| [:action, :controller].include?(key)}
|
40
|
-
]
|
41
|
-
end
|
42
|
-
|
43
32
|
class Configuration
|
44
|
-
attr_accessor :mongoid_yml, :environment
|
33
|
+
attr_accessor :mongoid_yml, :environment, :auth_email, :auth_password,
|
34
|
+
:no_auth
|
45
35
|
|
46
36
|
def validate!
|
47
37
|
if mongoid_yml.blank?
|
@@ -52,6 +42,10 @@ module Rack
|
|
52
42
|
puts 'rack-reqorder: No environment found, assuming development environment'
|
53
43
|
self.environment = :development
|
54
44
|
end
|
45
|
+
|
46
|
+
self.auth_email = 'admin@example.com' if auth_email.blank?
|
47
|
+
self.auth_password = 'password' if auth_password.blank?
|
48
|
+
self.no_auth = false if self.no_auth.blank?
|
55
49
|
end
|
56
50
|
end
|
57
51
|
end
|
@@ -79,3 +73,4 @@ require 'rack/reqorder/logger'
|
|
79
73
|
require 'rack/reqorder/monitor'
|
80
74
|
|
81
75
|
load 'rack/reqorder/tasks/routes.rake'
|
76
|
+
load 'rack/reqorder/tasks/test_database.rake'
|
data/lib/rack/reqorder/logger.rb
CHANGED
@@ -7,23 +7,24 @@ module Rack::Reqorder
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def call(environment)
|
10
|
-
|
10
|
+
rack_request = Rack::Request.new(environment.clone)
|
11
11
|
|
12
12
|
start = Time.now.to_f
|
13
13
|
begin
|
14
14
|
status, headers, body = @app.call(environment)
|
15
|
+
response = Rack::Response.new(body, status, headers)
|
15
16
|
rescue => exception
|
16
|
-
log_exception(exception, environment)
|
17
|
+
response = log_exception(exception, environment)
|
17
18
|
raise exception
|
19
|
+
ensure
|
20
|
+
response_time = Time.now.to_f - start
|
21
|
+
|
22
|
+
save_statistics(
|
23
|
+
rack_request: rack_request,
|
24
|
+
rack_response: response,
|
25
|
+
response_time: response_time
|
26
|
+
)
|
18
27
|
end
|
19
|
-
response_time = Time.now.to_f - start
|
20
|
-
|
21
|
-
#save_http_response(body, status, headers, http_request)
|
22
|
-
save_statistics(
|
23
|
-
rack_request: Rack::Request.new(environment),
|
24
|
-
rack_response: Rack::Response.new(body, status, headers),
|
25
|
-
response_time: response_time
|
26
|
-
)
|
27
28
|
|
28
29
|
return [status, headers, body]
|
29
30
|
end
|
@@ -42,15 +43,27 @@ module Rack::Reqorder
|
|
42
43
|
]
|
43
44
|
end
|
44
45
|
|
46
|
+
def route_template(request_path:, request_method:)
|
47
|
+
Rack::Reqorder.recognize_path(request_path, {method: request_method})
|
48
|
+
end
|
49
|
+
|
45
50
|
def save_statistics(rack_request:, rack_response:, response_time:)
|
46
51
|
route_path = RoutePath.find_or_create_by({
|
47
|
-
route:
|
52
|
+
route: route_template({
|
53
|
+
#response_status: rack_response.status,
|
54
|
+
request_path: rack_request.path,
|
55
|
+
request_method: rack_request.request_method
|
56
|
+
}),
|
48
57
|
http_method: rack_request.request_method
|
49
58
|
})
|
50
59
|
|
51
|
-
[:all.to_s, DateTime.now.hour.to_s].each do |key|
|
60
|
+
[:all.to_s, DateTime.now.utc.hour.to_s].each do |key|
|
52
61
|
statistic = route_path.send("statistic_#{key}".to_sym)
|
53
62
|
|
63
|
+
if key != :all && statistic && statistic.created_at.to_date < DateTime.now.utc.to_date
|
64
|
+
statistic = route_path.send("create_statistic_#{key}")
|
65
|
+
end
|
66
|
+
|
54
67
|
if statistic.nil?
|
55
68
|
statistic = route_path.send("create_statistic_#{key}")
|
56
69
|
end
|
@@ -79,7 +92,7 @@ module Rack::Reqorder
|
|
79
92
|
request = Rack::Request.new(environment)
|
80
93
|
|
81
94
|
route_path = RoutePath.find_or_create_by({
|
82
|
-
route: Rack::Reqorder.
|
95
|
+
route: Rack::Reqorder.recognize_path(request.path),
|
83
96
|
http_method: request.request_method
|
84
97
|
})
|
85
98
|
|
@@ -128,11 +141,12 @@ module Rack::Reqorder
|
|
128
141
|
path, line, _ = exception.backtrace.first.split(':')
|
129
142
|
end
|
130
143
|
|
131
|
-
|
132
144
|
app_fault = AppFault.find_or_create_by(
|
133
145
|
e_class: exception.class,
|
134
146
|
line: line.to_i,
|
135
|
-
filepath: path[1..-1]
|
147
|
+
filepath: path[1..-1],
|
148
|
+
route_path: http_request.route_path,
|
149
|
+
environment: app_environment
|
136
150
|
)
|
137
151
|
|
138
152
|
AppException.create(
|
@@ -147,7 +161,7 @@ module Rack::Reqorder
|
|
147
161
|
http_request: http_request
|
148
162
|
)
|
149
163
|
|
150
|
-
HttpResponse.create(
|
164
|
+
return HttpResponse.create(
|
151
165
|
status: 500,
|
152
166
|
http_request: http_request
|
153
167
|
)
|
@@ -165,5 +179,13 @@ module Rack::Reqorder
|
|
165
179
|
end
|
166
180
|
end
|
167
181
|
end
|
182
|
+
|
183
|
+
def app_environment
|
184
|
+
if Module.const_defined?(:Rails)
|
185
|
+
return Rails.env
|
186
|
+
else
|
187
|
+
return ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'unknown'
|
188
|
+
end
|
189
|
+
end
|
168
190
|
end
|
169
191
|
end
|
@@ -8,8 +8,13 @@ module Rack::Reqorder::Models
|
|
8
8
|
field :line, type: Integer
|
9
9
|
field :filepath, type: String
|
10
10
|
|
11
|
+
field :resolved, type: Boolean, default: false
|
12
|
+
|
13
|
+
field :environment, type: String
|
14
|
+
|
11
15
|
field :app_exceptions_count, type: Integer, default: 0
|
12
16
|
|
17
|
+
belongs_to :route_path, dependent: :nullify
|
13
18
|
has_many :app_exceptions, dependent: :destroy
|
14
19
|
|
15
20
|
def update_count!
|
@@ -9,32 +9,12 @@ module Rack::Reqorder::Models
|
|
9
9
|
|
10
10
|
has_many :http_requests, dependent: :destroy
|
11
11
|
|
12
|
-
embeds_one :statistic_0, class_name: 'Rack::Reqorder::Models::Statistic'
|
13
|
-
embeds_one :statistic_1, class_name: 'Rack::Reqorder::Models::Statistic'
|
14
|
-
embeds_one :statistic_2, class_name: 'Rack::Reqorder::Models::Statistic'
|
15
|
-
embeds_one :statistic_3, class_name: 'Rack::Reqorder::Models::Statistic'
|
16
|
-
embeds_one :statistic_4, class_name: 'Rack::Reqorder::Models::Statistic'
|
17
|
-
embeds_one :statistic_5, class_name: 'Rack::Reqorder::Models::Statistic'
|
18
|
-
embeds_one :statistic_6, class_name: 'Rack::Reqorder::Models::Statistic'
|
19
|
-
embeds_one :statistic_7, class_name: 'Rack::Reqorder::Models::Statistic'
|
20
|
-
embeds_one :statistic_8, class_name: 'Rack::Reqorder::Models::Statistic'
|
21
|
-
embeds_one :statistic_9, class_name: 'Rack::Reqorder::Models::Statistic'
|
22
|
-
embeds_one :statistic_10, class_name: 'Rack::Reqorder::Models::Statistic'
|
23
|
-
embeds_one :statistic_11, class_name: 'Rack::Reqorder::Models::Statistic'
|
24
|
-
embeds_one :statistic_12, class_name: 'Rack::Reqorder::Models::Statistic'
|
25
|
-
embeds_one :statistic_13, class_name: 'Rack::Reqorder::Models::Statistic'
|
26
|
-
embeds_one :statistic_14, class_name: 'Rack::Reqorder::Models::Statistic'
|
27
|
-
embeds_one :statistic_15, class_name: 'Rack::Reqorder::Models::Statistic'
|
28
|
-
embeds_one :statistic_16, class_name: 'Rack::Reqorder::Models::Statistic'
|
29
|
-
embeds_one :statistic_17, class_name: 'Rack::Reqorder::Models::Statistic'
|
30
|
-
embeds_one :statistic_18, class_name: 'Rack::Reqorder::Models::Statistic'
|
31
|
-
embeds_one :statistic_19, class_name: 'Rack::Reqorder::Models::Statistic'
|
32
|
-
embeds_one :statistic_20, class_name: 'Rack::Reqorder::Models::Statistic'
|
33
|
-
embeds_one :statistic_21, class_name: 'Rack::Reqorder::Models::Statistic'
|
34
|
-
embeds_one :statistic_22, class_name: 'Rack::Reqorder::Models::Statistic'
|
35
|
-
embeds_one :statistic_23, class_name: 'Rack::Reqorder::Models::Statistic'
|
36
|
-
embeds_one :statistic_24, class_name: 'Rack::Reqorder::Models::Statistic'
|
37
|
-
|
38
12
|
embeds_one :statistic_all, class_name: 'Rack::Reqorder::Models::Statistic'
|
13
|
+
|
14
|
+
0.upto(23) do |i|
|
15
|
+
embeds_one "statistic_#{i}", class_name: 'Rack::Reqorder::Models::Statistic'
|
16
|
+
end
|
17
|
+
|
18
|
+
has_one :app_fault, dependent: :destroy
|
39
19
|
end
|
40
20
|
end
|
@@ -20,7 +20,11 @@ module Rack::Reqorder::Models
|
|
20
20
|
field :xhr_count, type: Integer, default: 0
|
21
21
|
field :ssl_count, type: Integer, default: 0
|
22
22
|
|
23
|
-
embedded_in :route_path
|
23
|
+
embedded_in :route_path, inverse_of: :statistic_all
|
24
|
+
|
25
|
+
0.upto(23) do |i|
|
26
|
+
embedded_in :route_path, inverse_of: "statistic_#{i}"
|
27
|
+
end
|
24
28
|
|
25
29
|
def recalculate_average!(response_time)
|
26
30
|
self.avg_response_time = (
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'grape'
|
2
2
|
require 'grape-entity'
|
3
|
+
require 'rack/reqorder/monitor/helpers'
|
3
4
|
require 'rack/reqorder/monitor/entities'
|
4
5
|
require 'mongoid_hash_query'
|
5
6
|
require 'pry'
|
@@ -10,20 +11,32 @@ module Rack::Reqorder
|
|
10
11
|
end
|
11
12
|
|
12
13
|
module Rack::Reqorder::Monitor
|
14
|
+
|
13
15
|
class Api < Grape::API
|
14
16
|
include Rack::Reqorder::Models
|
15
17
|
include Rack::Reqorder::Monitor::Entities
|
16
18
|
|
17
19
|
helpers do
|
18
20
|
include MongoidHashQuery
|
21
|
+
include Rack::Reqorder::Monitor::Helpers
|
19
22
|
end
|
20
23
|
|
21
24
|
version 'v1', using: :path, vendor: 'foobar'
|
22
25
|
format :json
|
23
26
|
prefix :api
|
24
27
|
|
28
|
+
=begin
|
29
|
+
rescue_from Grape::Exceptions::ValidationErrors do |e|
|
30
|
+
error!({errors: e.send(:full_messages)}, 422)
|
31
|
+
end
|
32
|
+
=end
|
33
|
+
|
25
34
|
#collection routes
|
26
35
|
resource :route_paths do
|
36
|
+
before do
|
37
|
+
authorize_user!(headers) unless Rack::Reqorder.configuration.no_auth
|
38
|
+
end
|
39
|
+
|
27
40
|
get do
|
28
41
|
route_paths = apply_filters(RoutePath.all, params)
|
29
42
|
|
@@ -46,8 +59,23 @@ module Rack::Reqorder::Monitor
|
|
46
59
|
end
|
47
60
|
end
|
48
61
|
|
62
|
+
#collection routes
|
63
|
+
resource :route_path_24_statistics do
|
64
|
+
get do
|
65
|
+
route_paths = RoutePath.all
|
66
|
+
|
67
|
+
route_paths = apply_filters(route_paths, params)
|
68
|
+
|
69
|
+
present(route_paths, with: RoutePath24StatisticsEntity)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
49
73
|
#collection routes
|
50
74
|
resource :requests do
|
75
|
+
before do
|
76
|
+
authorize_user!(headers) unless Rack::Reqorder.configuration.no_auth
|
77
|
+
end
|
78
|
+
|
51
79
|
get do
|
52
80
|
requests = apply_filters(HttpRequest.all, params)
|
53
81
|
|
@@ -72,6 +100,10 @@ module Rack::Reqorder::Monitor
|
|
72
100
|
|
73
101
|
#collection routes
|
74
102
|
resource :responses do
|
103
|
+
before do
|
104
|
+
authorize_user!(headers) unless Rack::Reqorder.configuration.no_auth
|
105
|
+
end
|
106
|
+
|
75
107
|
get do
|
76
108
|
responses = HttpResponse.all
|
77
109
|
|
@@ -98,9 +130,15 @@ module Rack::Reqorder::Monitor
|
|
98
130
|
|
99
131
|
#collection routes
|
100
132
|
resource :faults do
|
133
|
+
before do
|
134
|
+
authorize_user!(headers) unless Rack::Reqorder.configuration.no_auth
|
135
|
+
end
|
136
|
+
|
101
137
|
get do
|
102
138
|
faults = AppFault.all
|
103
139
|
|
140
|
+
environments = faults.group_by(&:environment).keys
|
141
|
+
|
104
142
|
faults = apply_filters(faults, params)
|
105
143
|
|
106
144
|
meta_aggregations = aggregations(faults, params)
|
@@ -110,7 +148,7 @@ module Rack::Reqorder::Monitor
|
|
110
148
|
present_with_meta(
|
111
149
|
faults,
|
112
150
|
present(faults, with: FaultEntity),
|
113
|
-
meta_aggregations
|
151
|
+
meta_aggregations.merge(environments: environments)
|
114
152
|
)
|
115
153
|
end
|
116
154
|
|
@@ -119,11 +157,28 @@ module Rack::Reqorder::Monitor
|
|
119
157
|
get do
|
120
158
|
present(AppFault.find(params[:id]), with: FaultEntity)
|
121
159
|
end
|
160
|
+
|
161
|
+
params do
|
162
|
+
requires :fault, type: Hash do
|
163
|
+
optional :resolved, type: Boolean
|
164
|
+
end
|
165
|
+
end
|
166
|
+
put do
|
167
|
+
fault = AppFault.find(params[:id])
|
168
|
+
fault.resolved = declared(params)[:fault][:resolved]
|
169
|
+
fault.save!
|
170
|
+
|
171
|
+
present(fault, with: FaultEntity)
|
172
|
+
end
|
122
173
|
end
|
123
174
|
end
|
124
175
|
|
125
176
|
#collection routes
|
126
177
|
resource :exceptions do
|
178
|
+
before do
|
179
|
+
authorize_user!(headers) unless Rack::Reqorder.configuration.no_auth
|
180
|
+
end
|
181
|
+
|
127
182
|
get do
|
128
183
|
exceptions = AppException.all
|
129
184
|
|
@@ -148,24 +203,39 @@ module Rack::Reqorder::Monitor
|
|
148
203
|
end
|
149
204
|
end
|
150
205
|
|
206
|
+
|
207
|
+
params do
|
208
|
+
requires :user, type: Hash do
|
209
|
+
requires :email, type: String
|
210
|
+
requires :password, type: String
|
211
|
+
end
|
212
|
+
end
|
213
|
+
resource :sessions do
|
214
|
+
post do
|
215
|
+
authenticate_user!(declared(params))
|
216
|
+
|
217
|
+
present(Object.new, with: SessionEntity)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
151
221
|
helpers do
|
152
222
|
def present_with_meta(object, hash, extra_meta)
|
153
223
|
hash[:meta] = {
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
224
|
+
current_page: object.current_page,
|
225
|
+
next_page: object.next_page,
|
226
|
+
prev_page: object.prev_page,
|
227
|
+
total_pages: object.total_pages,
|
228
|
+
total_count: object.total_count
|
159
229
|
}.merge(extra_meta)
|
160
230
|
|
161
231
|
return hash
|
162
232
|
end
|
163
233
|
|
164
234
|
def paginate(object, params)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
235
|
+
object = object.page(params[:page] || 1).per(params[:per_page] || 30)
|
236
|
+
object = object.skip(params[:skip]) if params[:skip]
|
237
|
+
|
238
|
+
return object
|
169
239
|
end
|
170
240
|
end
|
171
241
|
|
@@ -38,9 +38,11 @@ module Rack::Reqorder::Monitor
|
|
38
38
|
expose :http_method
|
39
39
|
expose :statistic_all, using: StatisticEntity
|
40
40
|
|
41
|
+
=begin
|
41
42
|
1.upto(24) do |num|
|
42
43
|
expose "statistic_#{num}", using: StatisticEntity
|
43
44
|
end
|
45
|
+
=end
|
44
46
|
|
45
47
|
with_options(format_with: :iso_timestamp) do
|
46
48
|
expose :created_at
|
@@ -48,6 +50,55 @@ module Rack::Reqorder::Monitor
|
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
53
|
+
class RoutePath24StatisticsEntity < Grape::Entity
|
54
|
+
root :route_path_25_statistics
|
55
|
+
present_collection true
|
56
|
+
|
57
|
+
exposures = proc{|aggrs, field|
|
58
|
+
aggrs.each do |aggr|
|
59
|
+
expose aggr do |route_path, options|
|
60
|
+
today_array = []
|
61
|
+
yesterday_array = []
|
62
|
+
|
63
|
+
now = DateTime.now.utc.hour
|
64
|
+
|
65
|
+
0.upto(now) do |i|
|
66
|
+
today_array.push(
|
67
|
+
route_path[:items].where(
|
68
|
+
"statistic_#{i}.created_at".to_sym.gte => DateTime.now.utc.to_date
|
69
|
+
).send(aggr,("statistic_#{i}.#{field}"))
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
if now <23
|
74
|
+
(now+1).upto(23) do |i|
|
75
|
+
yesterday_array.push(
|
76
|
+
route_path[:items].where(
|
77
|
+
"statistic_#{i}.created_at".to_sym.gte => (DateTime.now.utc.to_date - 1)
|
78
|
+
).send(aggr,("statistic_#{i}.#{field}"))
|
79
|
+
)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
[yesterday_array,today_array].flatten
|
84
|
+
end
|
85
|
+
end
|
86
|
+
}
|
87
|
+
|
88
|
+
[:http_requests_count, :statuses_2xx, :statuses_3xx, :statuses_4xx,
|
89
|
+
:statuses_401, :statuses_404, :statuses_422, :statuses_5xx,
|
90
|
+
:xhr_count, :ssl_count
|
91
|
+
].each do |field|
|
92
|
+
expose field do
|
93
|
+
exposures.call([:sum], field)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
expose :avg_response_time do
|
98
|
+
exposures.call([:avg], :avg_response_time)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
51
102
|
class RequestEntity < BaseEntity
|
52
103
|
root :requests, :request
|
53
104
|
|
@@ -100,15 +151,21 @@ module Rack::Reqorder::Monitor
|
|
100
151
|
expose :e_class
|
101
152
|
expose :line
|
102
153
|
expose :filepath
|
154
|
+
expose :resolved
|
103
155
|
expose :app_exceptions_count, as: :exceptions_count
|
156
|
+
expose :environment
|
104
157
|
expose :message do |fault, options|
|
105
|
-
fault.app_exceptions.try(:
|
158
|
+
fault.app_exceptions.try(:last).try(:message)
|
106
159
|
end
|
107
160
|
|
108
161
|
expose :app_exception_ids, as: :exception_ids do |fault, options|
|
109
162
|
fault.app_exception_ids.map(&:to_s).first(100)
|
110
163
|
end
|
111
164
|
|
165
|
+
with_options(format_with: :association_id) do
|
166
|
+
expose :route_path, as: :route_path_id
|
167
|
+
end
|
168
|
+
|
112
169
|
with_options(format_with: :iso_timestamp) do
|
113
170
|
expose :created_at
|
114
171
|
expose :updated_at
|
@@ -136,5 +193,23 @@ module Rack::Reqorder::Monitor
|
|
136
193
|
end
|
137
194
|
|
138
195
|
end
|
196
|
+
|
197
|
+
class SessionEntity < Grape::Entity
|
198
|
+
expose :id do |status, options|
|
199
|
+
1
|
200
|
+
end
|
201
|
+
|
202
|
+
expose :email do |status, options|
|
203
|
+
Rack::Reqorder.configuration.auth_email
|
204
|
+
end
|
205
|
+
|
206
|
+
expose :token do |status, options|
|
207
|
+
#need user object...
|
208
|
+
Digest::MD5.hexdigest(
|
209
|
+
Rack::Reqorder.configuration.auth_email +
|
210
|
+
Rack::Reqorder.configuration.auth_password
|
211
|
+
)
|
212
|
+
end
|
213
|
+
end
|
139
214
|
end
|
140
215
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Rack::Reqorder::Monitor
|
2
|
+
module Helpers
|
3
|
+
def authorize_user!(headers)
|
4
|
+
authorize_user(headers) ? true : error!('403 Forbidden', 403)
|
5
|
+
end
|
6
|
+
|
7
|
+
def authenticate_user!(params)
|
8
|
+
authenticate_user(params) ? true : error!('401 Unauthorized', 401)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
#monkeypatch these 2 methods if you want to provide custom authentication/authorization
|
13
|
+
def authorize_user(headers)
|
14
|
+
token, options = AuthorizationHeader.token_and_options(headers)
|
15
|
+
|
16
|
+
user_email = options.blank?? nil : options[:email]
|
17
|
+
|
18
|
+
correct_email = user_email == Rack::Reqorder.configuration.auth_email
|
19
|
+
correct_token = token == user_email_password_md5
|
20
|
+
|
21
|
+
return (correct_email && correct_token) ? true : false
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def authenticate_user(params)
|
26
|
+
email = params.user.email
|
27
|
+
password = params.user.password
|
28
|
+
|
29
|
+
correct_email = email == Rack::Reqorder.configuration.auth_email
|
30
|
+
correct_password = password == Rack::Reqorder.configuration.auth_password
|
31
|
+
|
32
|
+
return (correct_email && correct_password)? true : false
|
33
|
+
end
|
34
|
+
|
35
|
+
def user_email_password_md5(user: nil)
|
36
|
+
#if user.nil?
|
37
|
+
Digest::MD5.hexdigest(
|
38
|
+
Rack::Reqorder.configuration.auth_email +
|
39
|
+
Rack::Reqorder.configuration.auth_password
|
40
|
+
)
|
41
|
+
#else
|
42
|
+
#end
|
43
|
+
end
|
44
|
+
#taken from rails ActionController::HttpAuthentication::Token ^_^
|
45
|
+
class AuthorizationHeader
|
46
|
+
class << self
|
47
|
+
TOKEN_KEY = 'token='
|
48
|
+
TOKEN_REGEX = /^(Token|Bearer) /
|
49
|
+
AUTHN_PAIR_DELIMITERS = /(?:,|;|\t+)/
|
50
|
+
|
51
|
+
def token_and_options(headers)
|
52
|
+
authorization_request = headers['Authorization']
|
53
|
+
|
54
|
+
if authorization_request[TOKEN_REGEX]
|
55
|
+
params = token_params_from authorization_request
|
56
|
+
[params.shift[1], Hash[params].with_indifferent_access]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def token_params_from(auth)
|
63
|
+
rewrite_param_values params_array_from raw_params auth
|
64
|
+
end
|
65
|
+
|
66
|
+
# Takes raw_params and turns it into an array of parameters
|
67
|
+
def params_array_from(raw_params)
|
68
|
+
raw_params.map { |param| param.split %r/=(.+)?/ }
|
69
|
+
end
|
70
|
+
|
71
|
+
# This removes the <tt>"</tt> characters wrapping the value.
|
72
|
+
def rewrite_param_values(array_params)
|
73
|
+
array_params.each { |param| (param[1] || "").gsub! %r/^"|"$/, '' }
|
74
|
+
end
|
75
|
+
|
76
|
+
# This method takes an authorization body and splits up the key-value
|
77
|
+
# pairs by the standardized <tt>:</tt>, <tt>;</tt>, or <tt>\t</tt>
|
78
|
+
# delimiters defined in +AUTHN_PAIR_DELIMITERS+.
|
79
|
+
def raw_params(auth)
|
80
|
+
_raw_params = auth.sub(TOKEN_REGEX, '').split(/\s*#{AUTHN_PAIR_DELIMITERS}\s*/)
|
81
|
+
|
82
|
+
if !(_raw_params.first =~ %r{\A#{TOKEN_KEY}})
|
83
|
+
_raw_params[0] = "#{TOKEN_KEY}#{_raw_params.first}"
|
84
|
+
end
|
85
|
+
|
86
|
+
_raw_params
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Rack
|
2
|
+
module Reqorder
|
3
|
+
module RailsRecognizer
|
4
|
+
def prefixes
|
5
|
+
return @prefixes unless @prefixes.blank?
|
6
|
+
|
7
|
+
@prefixes = {} #{'/mount_prefix' => {search_method: xxx_recognize_path, rack_app: xxx}}
|
8
|
+
Rails.application.routes.routes.routes.select{|r| r.defaults.blank?}.each do |route|
|
9
|
+
__superclass = route.app.try(:superclass) || route.app.try(:app).try(:superclass)
|
10
|
+
|
11
|
+
next unless __superclass
|
12
|
+
|
13
|
+
case __superclass.to_s
|
14
|
+
when Sinatra::Base.to_s
|
15
|
+
@prefixes[route.path.spec.try(:left).to_s + route.path.spec.try(:right).to_s] = {
|
16
|
+
search_method: :sinatra_recognize_path,
|
17
|
+
rack_app: route.app.try(:superclass).nil? ? route.app.app : route.app
|
18
|
+
}
|
19
|
+
when Rails::Engine.to_s
|
20
|
+
@prefixes[route.path.spec.try(:left).to_s + route.path.spec.try(:right).to_s] = {
|
21
|
+
search_method: :rails_recognize_path,
|
22
|
+
rack_app: route.app.try(:superclass).nil? ? route.app.app : route.app
|
23
|
+
}
|
24
|
+
when Grape::API.to_s
|
25
|
+
@prefixes[route.path.spec.try(:left).to_s + route.path.spec.try(:right).to_s] = {
|
26
|
+
search_method: :grape_recognize_path,
|
27
|
+
rack_app: route.app.try(:superclass).nil? ? route.app.app : route.app
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
return @prefixes
|
33
|
+
end
|
34
|
+
|
35
|
+
def rails_paths(rails_app)
|
36
|
+
paths = {}
|
37
|
+
rails_app.routes.routes.routes.reverse.each do |route|
|
38
|
+
paths[route.defaults] = route.path.spec.to_s.gsub('(.:format)', '')
|
39
|
+
end
|
40
|
+
|
41
|
+
return paths
|
42
|
+
end
|
43
|
+
|
44
|
+
def recognize_unknown_path
|
45
|
+
prefixes.each do |prefix, engine|
|
46
|
+
if path_uri.start_with?(prefix)
|
47
|
+
return prefix
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
return ''
|
52
|
+
end
|
53
|
+
|
54
|
+
def recognize_path(path_uri, options = {})
|
55
|
+
prefixes.each do |prefix, engine|
|
56
|
+
if path_uri.start_with?(prefix)
|
57
|
+
return prefix + self.send(engine[:search_method].to_sym, {
|
58
|
+
path_uri: path_uri.gsub(prefix, ''),
|
59
|
+
rack_app: engine[:rack_app],
|
60
|
+
options: options
|
61
|
+
})
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
begin
|
66
|
+
return rails_recognize_path(
|
67
|
+
path_uri: path_uri,
|
68
|
+
rack_app: Rails.application,
|
69
|
+
options: options
|
70
|
+
)
|
71
|
+
rescue ActionController::RoutingError
|
72
|
+
return "/#{path_uri.split('/')[1]}"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#rack_app is basically a rails app here but we keep it for the sake of the interface
|
77
|
+
def rails_recognize_path(path_uri:, rack_app:, options: {})
|
78
|
+
memoized_var = "@#{rack_app.class.to_s.split('::').join('_').downcase}".to_sym
|
79
|
+
|
80
|
+
if self.instance_variable_get(memoized_var).nil?
|
81
|
+
self.instance_variable_set(memoized_var, rails_paths(rack_app))
|
82
|
+
end
|
83
|
+
|
84
|
+
Rack::Reqorder.instance_variable_get(memoized_var)[
|
85
|
+
rack_app.routes.recognize_path(path_uri, options)
|
86
|
+
.select{|key, value| [:action, :controller].include?(key)}
|
87
|
+
]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
module GrapeRecognizer
|
92
|
+
def recognize_path(path_uri, options = {})
|
93
|
+
raise 'not implemented yet'
|
94
|
+
end
|
95
|
+
|
96
|
+
def grape_recognize_path(path_uri:, rack_app:, options: {})
|
97
|
+
path_uri = '/' if path_uri.blank?
|
98
|
+
|
99
|
+
rack_app.routes.each do |route|
|
100
|
+
route_options = route.instance_variable_get(:@options)
|
101
|
+
if route_options[:method] == options[:method] && route_options[:compiled] =~ path_uri
|
102
|
+
if route_options[:method] == "OPTIONS"
|
103
|
+
return route_options[:path].
|
104
|
+
gsub('(.json)', '')
|
105
|
+
else
|
106
|
+
return route_options[:path].
|
107
|
+
gsub(':version', route_options[:version]).
|
108
|
+
gsub('(.json)', '')
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
#assets in grape? well you never know..
|
114
|
+
if path_uri.end_with?('.js')
|
115
|
+
return '/js_asset'
|
116
|
+
elsif path_uri.end_with?('.css')
|
117
|
+
return '/css_asset'
|
118
|
+
elsif path_uri.end_with?('.png', 'jpg')
|
119
|
+
return '/css_asset'
|
120
|
+
else
|
121
|
+
return '/unknown' #path_uri
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
module SinatraRecognizer
|
127
|
+
def recognize_path(path_uri, options = {})
|
128
|
+
raise 'not implemented yet'
|
129
|
+
end
|
130
|
+
|
131
|
+
def sinatra_recognize_path(path_uri:, rack_app:, options: {})
|
132
|
+
path_uri = '/' if path_uri.blank?
|
133
|
+
|
134
|
+
rack_app.routes[options[:method].to_s.upcase].each do |r|
|
135
|
+
if r.first =~ path_uri
|
136
|
+
return r.first.to_s.
|
137
|
+
gsub('([^\\/?#]+)', ":#{r[1].first}").
|
138
|
+
gsub('\\z)','').gsub('(?-mix:\\A', '').
|
139
|
+
gsub('\\','')
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
if path_uri.end_with?('.js')
|
144
|
+
return '/js_asset'
|
145
|
+
elsif path_uri.end_with?('.css')
|
146
|
+
return '/css_asset'
|
147
|
+
elsif path_uri.end_with?('.png', 'jpg')
|
148
|
+
return '/css_asset'
|
149
|
+
else
|
150
|
+
return '/unknown' #path_uri
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
if respond_to?(:namespace, true)
|
2
|
+
namespace 'rack-reqorder' do
|
3
|
+
desc 'rack-monitor API routes'
|
4
|
+
task :test_database => :environment do
|
5
|
+
env = ENV["RACK_ENV"] || ENV["RAILS_ENV"] || Rails.env
|
6
|
+
return 'Available only under development env' unless env == 'development'
|
7
|
+
|
8
|
+
require_relative '../../../../spec/rack/factories/statistics.rb'
|
9
|
+
require_relative '../../../../spec/rack/factories/route_paths.rb'
|
10
|
+
require_relative '../../../../spec/rack/factories/app_faults.rb'
|
11
|
+
|
12
|
+
10.times { FactoryGirl.create(:route_path) }
|
13
|
+
|
14
|
+
FactoryGirl.create(
|
15
|
+
:route_path,
|
16
|
+
route: '/rack-reqorder/api/v1/route_path_24_statistics',
|
17
|
+
http_method: 'GET'
|
18
|
+
)
|
19
|
+
|
20
|
+
FactoryGirl.create(
|
21
|
+
:route_path,
|
22
|
+
route: '/rack-reqorder/api/v1/route_paths',
|
23
|
+
http_method: 'GET'
|
24
|
+
)
|
25
|
+
|
26
|
+
40.times { FactoryGirl.create(:app_fault) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/rack-reqorder.gemspec
CHANGED
@@ -6,12 +6,12 @@ require 'rack/reqorder/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "rack-reqorder"
|
8
8
|
spec.version = Rack::Reqorder::VERSION
|
9
|
-
spec.authors = ["Filippos Vasilakis"]
|
10
|
-
spec.email = ["vasilakisfil@gmail.com"]
|
9
|
+
spec.authors = ["Filippos Vasilakis", "Kollegorna"]
|
10
|
+
spec.email = ["vasilakisfil@gmail.com", "admin@kollegorna.se"]
|
11
11
|
|
12
12
|
spec.summary = %q{Request recorder and analyzer for rack apps}
|
13
13
|
spec.description = %q{Request recorder and analyzer for rack apps}
|
14
|
-
spec.homepage = ""
|
14
|
+
spec.homepage = "https://github.com/kollegorna/rack-reqorder"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
@@ -20,8 +20,12 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.8"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "pry"
|
24
|
+
spec.add_development_dependency "factory_girl", "~> 4.0"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_development_dependency "faker"
|
23
27
|
spec.add_dependency "mongoid", "~> 4.0.0"
|
24
|
-
spec.add_dependency "activesupport", "
|
28
|
+
spec.add_dependency "activesupport", ">4.0.0"
|
25
29
|
spec.add_dependency "grape"
|
26
30
|
spec.add_dependency "grape-entity"
|
27
31
|
spec.add_dependency "kaminari"
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-reqorder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Filippos Vasilakis
|
8
|
+
- Kollegorna
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2015-
|
12
|
+
date: 2015-10-12 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: bundler
|
@@ -38,6 +39,62 @@ dependencies:
|
|
38
39
|
- - "~>"
|
39
40
|
- !ruby/object:Gem::Version
|
40
41
|
version: '10.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: pry
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: factory_girl
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '4.0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '4.0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: faker
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
41
98
|
- !ruby/object:Gem::Dependency
|
42
99
|
name: mongoid
|
43
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,16 +113,16 @@ dependencies:
|
|
56
113
|
name: activesupport
|
57
114
|
requirement: !ruby/object:Gem::Requirement
|
58
115
|
requirements:
|
59
|
-
- - "
|
116
|
+
- - ">"
|
60
117
|
- !ruby/object:Gem::Version
|
61
|
-
version: 4.
|
118
|
+
version: 4.0.0
|
62
119
|
type: :runtime
|
63
120
|
prerelease: false
|
64
121
|
version_requirements: !ruby/object:Gem::Requirement
|
65
122
|
requirements:
|
66
|
-
- - "
|
123
|
+
- - ">"
|
67
124
|
- !ruby/object:Gem::Version
|
68
|
-
version: 4.
|
125
|
+
version: 4.0.0
|
69
126
|
- !ruby/object:Gem::Dependency
|
70
127
|
name: grape
|
71
128
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,6 +196,7 @@ dependencies:
|
|
139
196
|
description: Request recorder and analyzer for rack apps
|
140
197
|
email:
|
141
198
|
- vasilakisfil@gmail.com
|
199
|
+
- admin@kollegorna.se
|
142
200
|
executables: []
|
143
201
|
extensions: []
|
144
202
|
extra_rdoc_files: []
|
@@ -164,11 +222,14 @@ files:
|
|
164
222
|
- lib/rack/reqorder/models/statistic.rb
|
165
223
|
- lib/rack/reqorder/monitor.rb
|
166
224
|
- lib/rack/reqorder/monitor/entities.rb
|
225
|
+
- lib/rack/reqorder/monitor/helpers.rb
|
226
|
+
- lib/rack/reqorder/route_recognizers.rb
|
167
227
|
- lib/rack/reqorder/services/backtrace_cleaner.rb
|
168
228
|
- lib/rack/reqorder/tasks/routes.rake
|
229
|
+
- lib/rack/reqorder/tasks/test_database.rake
|
169
230
|
- lib/rack/reqorder/version.rb
|
170
231
|
- rack-reqorder.gemspec
|
171
|
-
homepage:
|
232
|
+
homepage: https://github.com/kollegorna/rack-reqorder
|
172
233
|
licenses:
|
173
234
|
- MIT
|
174
235
|
metadata: {}
|
@@ -188,7 +249,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
188
249
|
version: '0'
|
189
250
|
requirements: []
|
190
251
|
rubyforge_project:
|
191
|
-
rubygems_version: 2.4.
|
252
|
+
rubygems_version: 2.4.8
|
192
253
|
signing_key:
|
193
254
|
specification_version: 4
|
194
255
|
summary: Request recorder and analyzer for rack apps
|