rack-reqorder 0.4.8 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f25501aa934652db3f5cc6a5683838a1b6bd1665
4
- data.tar.gz: 9c47d97e22515eac1bde1ad85bfcd259b77a7283
3
+ metadata.gz: a0d9d5b4fe1dadfe5ec2b8f248fb7862378ddd1b
4
+ data.tar.gz: 238cce079cb09e7ef03f9d11b756a5da73386557
5
5
  SHA512:
6
- metadata.gz: 0ee9d658036006d1bd825e7dbc94d1e22cb186682cc5fa31421e2f538c103a8e0e2e66e4a9b65ee82ba87cc4c9d9ff8839999d923673ceeb178d45c946940587
7
- data.tar.gz: 00241ea89a34078c7be449ffd537a5f14b181b6dbe79c7e94d02d4368904ffaaf7db1076150119def9155a2cd70aa25967fbcd33018276c07e087a6e1ce5f871
6
+ metadata.gz: b2c55e3216b4d70fc7fe3711b328781c5fad3e18526d545827d7163d150e9713cd871e8d9e7c2bf559b97075de58c0be47aff23a34261e5e1a3f33dc45ebc433
7
+ data.tar.gz: 91c820d63adea800dd5c5ad1fec1c6257da3c26728822ca3fc7da43ec962cf4c8a9aea65da4d1658634fa93c795a1d70694a3602900a32915211891584e41cfc
data/README.md CHANGED
@@ -4,12 +4,21 @@ Simple gem for monitoring Rack apps. Uses MongoDB. It can be used in combination
4
4
  with [rack-reqorder-monitor](https://github.com/kollegorna/rack-reqorder-monitor).
5
5
 
6
6
  ## Introduction
7
- Simple gem that sits on top of Rack and records request/response statistics
8
- as well as monitors for exceptions. It saves everything in MongoDB and exposes
9
- a simple API for retrieving these data.
7
+ Simple gem that sits on top of Rack and can:
8
+
9
+ - monitors for exceptions
10
+ - record full requests/responses, based on a header
11
+ - record request/response statistics
12
+
13
+ It saves everything in MongoDB and exposes simple API for retrieving these data.
10
14
 
11
15
  The API is very robust, built with the help of [mongoid_hash_query](https://github.com/kollegorna/mongoid_hash_query).
12
16
 
17
+ A simple, default, dashboard is build in ember can be found [here](https://github.com/kollegorna/rack-reqorder-monitor).
18
+
19
+ At the moment, Rails, Sinatra and Grape are supported.
20
+ We are looking forward to add support for Hanami (ex-lotus)
21
+
13
22
  ## Installation
14
23
 
15
24
  Add this line to your application's Gemfile:
@@ -44,20 +53,16 @@ end
44
53
 
45
54
  Rack::Reqorder.boot!
46
55
 
56
+ #if you run on development mode
47
57
  Rails.application.config.middleware.insert_after(ActionDispatch::DebugExceptions , Rack::Reqorder::Logger)
48
-
49
- #rack-cors also needed
50
- Rails.application.config.middleware.insert_before 0, "Rack::Cors" do
51
- allow do
52
- origins '*'
53
- resource '*', :headers => :any, :methods => [:get, :post, :options]
54
- end
55
- end
58
+ #or if run on production
59
+ #Rails.application.config.middleware.insert_after(0, Rack::Reqorder::Logger)
60
+ ```
61
+ Then in routes.rb enable the API for the [rack-reqorder-monitor](https://github.com/kollegorna/rack-reqorder-monitor).
62
+ ```ruby
63
+ require 'rack/reqorder/monitor'
64
+ mount Rack::Reqorder::Monitor::Api => '/rack-reqorder'
56
65
  ```
57
- Please note that you can configure origins and resource depending on how you
58
- mount the rack-monitor engine and where you deploy your front-end.
59
-
60
- For viewing your statistics please check [rack-reqorder-monitor](https://github.com/kollegorna/rack-reqorder-monitor)
61
66
 
62
67
  ## Development
63
68
 
@@ -67,7 +72,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
67
72
 
68
73
  ## Contributing
69
74
 
70
- 1. Fork it ( https://github.com/[my-github-username]/rack-reqorder/fork )
75
+ 1. Fork it ( https://github.com/kollegorna/rack-reqorder/fork )
71
76
  2. Create your feature branch (`git checkout -b my-new-feature`)
72
77
  3. Commit your changes (`git commit -am 'Add some feature'`)
73
78
  4. Push to the branch (`git push origin my-new-feature`)
@@ -2,6 +2,7 @@ require 'rack/reqorder/version'
2
2
  require 'active_support/inflector'
3
3
  require 'mongoid'
4
4
  require 'kaminari'
5
+ require 'rack/cors'
5
6
  require 'kaminari/models/mongoid_extension'
6
7
  require 'rack/reqorder/route_recognizers'
7
8
 
@@ -31,7 +32,7 @@ module Rack
31
32
 
32
33
  class Configuration
33
34
  attr_accessor :mongoid_yml, :environment, :auth_email, :auth_password,
34
- :no_auth
35
+ :no_auth, :metrics_monitoring, :exception_monitoring, :request_monitoring
35
36
 
36
37
  def validate!
37
38
  if mongoid_yml.blank?
@@ -42,18 +43,24 @@ module Rack
42
43
  self.environment = app_environment
43
44
  end
44
45
 
45
- self.auth_email = 'admin@example.com' if auth_email.blank?
46
- self.auth_password = 'password' if auth_password.blank?
47
- self.no_auth = false if self.no_auth.blank?
48
46
  end
49
47
 
50
48
  def app_environment
51
49
  if Module.const_defined?(:Rails)
52
50
  return Rails.env
53
51
  else
54
- return ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'staging'
52
+ return ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'unknown'
55
53
  end
56
54
  end
55
+
56
+ def initialize
57
+ self.auth_email = 'admin@example.com' if auth_email.blank?
58
+ self.auth_password = 'password' if auth_password.blank?
59
+ self.no_auth = false if self.no_auth.blank?
60
+ self.metrics_monitoring = true if self.metrics_monitoring.blank?
61
+ self.exception_monitoring = true if self.exception_monitoring.blank?
62
+ self.request_monitoring = true if self.request_monitoring.blank?
63
+ end
57
64
  end
58
65
  end
59
66
  end
@@ -75,9 +82,9 @@ require 'rack/reqorder/models/route_path'
75
82
  require 'rack/reqorder/models/http_response'
76
83
  require 'rack/reqorder/models/app_fault'
77
84
  require 'rack/reqorder/models/app_exception'
85
+ require 'rack/reqorder/models/recording'
78
86
  require 'rack/reqorder/services/backtrace_cleaner'
79
87
  require 'rack/reqorder/logger'
80
88
  require 'rack/reqorder/monitor'
81
89
 
82
90
  load 'rack/reqorder/tasks/routes.rake'
83
- load 'rack/reqorder/tasks/test_database.rake'
@@ -9,33 +9,57 @@ module Rack::Reqorder
9
9
  def call(environment)
10
10
  rack_request = Rack::Request.new(environment.clone)
11
11
 
12
+ http_request = record_request(rack_request) if conf.request_monitoring
13
+
12
14
  start = Time.now.to_f
13
15
  begin
14
16
  status, headers, body = @app.call(environment)
15
- response = Rack::Response.new(body, status, headers)
17
+ rack_response = Rack::Response.new(body, status, headers)
16
18
  rescue => exception
17
- response = log_exception(exception, environment)
19
+ rack_response = log_exception(exception, rack_request) if conf.exception_monitoring
20
+
18
21
  raise exception
19
22
  ensure
20
- response_time = Time.now.to_f - start
21
-
22
- if response
23
- save_statistics(
24
- rack_request: rack_request,
25
- rack_response: response,
26
- response_time: response_time
27
- )
28
- end
23
+ record_statistics(rack_request, rack_response, Time.now.to_f - start)
29
24
  end
25
+ record_response(rack_response, http_request) if conf.request_monitoring
30
26
 
31
27
  return [status, headers, body]
32
28
  end
33
29
 
34
30
  private
31
+ def record_statistics(rack_request, rack_response, response_time)
32
+ if rack_response && conf.metrics_monitoring
33
+ save_statistics(
34
+ rack_request: rack_request,
35
+ rack_response: rack_response,
36
+ response_time: response_time
37
+ )
38
+ end
39
+ end
40
+
41
+ def record_request(rack_request)
42
+ request_headers = extract_all_headers(rack_request.env)
43
+ recording = nil
44
+
45
+ Recording.enabled.all.each do |rec|
46
+ if request_headers[rec.http_header] == rec.http_header_value
47
+ recording = rec and break
48
+ end
49
+ end
50
+
51
+ return save_http_request(rack_request, recording)
52
+ end
35
53
 
36
- def extract_all_headers(request)
54
+ def record_response(rack_response, http_request)
55
+ if http_request && http_request.recording
56
+ return save_http_response(rack_response, http_request)
57
+ end
58
+ end
59
+
60
+ def extract_all_headers(env)
37
61
  Hash[
38
- request.env.select{|k,v|
62
+ env.select{|k,v|
39
63
  k.start_with? 'HTTP_'
40
64
  }.map{|k,v|
41
65
  [k.gsub('HTTP_','').upcase, v]
@@ -90,44 +114,46 @@ module Rack::Reqorder
90
114
  end
91
115
  end
92
116
 
93
- def save_http_request(environment)
94
- request = Rack::Request.new(environment)
95
117
 
96
- route_path = RoutePath.find_or_create_by({
97
- route: Rack::Reqorder.recognize_path(request.path),
98
- http_method: request.request_method
99
- })
118
+ def save_http_request(rack_request, recording = nil)
119
+ if not recording
120
+ route_path = RoutePath.find_or_create_by({
121
+ route: Rack::Reqorder.recognize_path(rack_request.path),
122
+ http_method: rack_request.request_method
123
+ })
124
+ end
100
125
 
101
126
  HttpRequest.create({
102
- ip: request.ip,
103
- url: request.url,
104
- scheme: request.scheme,
105
- base_url: request.base_url,
106
- port: request.port,
107
- path: request.path,
108
- full_path: request.fullpath,
109
- http_method: request.request_method,
110
- headers: extract_all_headers(request),
111
- params: request.params,
112
- ssl: request.ssl?,
113
- xhr: request.xhr?,
114
- route_path: route_path
127
+ ip: rack_request.ip,
128
+ url: rack_request.url,
129
+ scheme: rack_request.scheme,
130
+ base_url: rack_request.base_url,
131
+ port: rack_request.port,
132
+ path: rack_request.path,
133
+ full_path: rack_request.fullpath,
134
+ http_method: rack_request.request_method,
135
+ headers: extract_all_headers(rack_request.env),
136
+ params: rack_request.params,
137
+ ssl: rack_request.ssl?,
138
+ xhr: rack_request.xhr?,
139
+ route_path: recording ? nil : route_path,
140
+ recording: recording ? recording : nil
115
141
  })
116
142
  end
117
143
 
118
- def save_http_response(body, status, headers, http_request)
119
- response = Rack::Response.new(body, status, headers)
120
-
144
+ def save_http_response(rack_response, http_request)
121
145
  HttpResponse.create(
122
- headers: response.headers,
123
- #body: response.body.first,
124
- status: response.status.to_i,
125
- http_request: http_request
146
+ headers: rack_response.headers,
147
+ body: rack_response.body.first,
148
+ status: rack_response.status.to_i,
149
+ length: rack_response.length,
150
+ http_request: http_request,
151
+ recording: http_request.recording.nil? ? nil : http_request.recording
126
152
  )
127
153
  end
128
154
 
129
- def log_exception(exception, environment)
130
- http_request = save_http_request(environment)
155
+ def log_exception(exception, rack_request)
156
+ http_request = save_http_request(rack_request)
131
157
 
132
158
  bc = BacktraceCleaner.new
133
159
  bc.add_filter { |line| line.gsub(Rails.root.to_s, '') }
@@ -147,7 +173,7 @@ module Rack::Reqorder
147
173
  e_class: exception.class,
148
174
  line: line.to_i,
149
175
  filepath: path[1..-1],
150
- environment: app_environment
176
+ environment: conf.environment
151
177
  )
152
178
 
153
179
  AppException.create(
@@ -181,12 +207,8 @@ module Rack::Reqorder
181
207
  end
182
208
  end
183
209
 
184
- def app_environment
185
- if Module.const_defined?(:Rails)
186
- return Rails.env
187
- else
188
- return ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'unknown'
189
- end
210
+ def conf
211
+ Rack::Reqorder.configuration
190
212
  end
191
213
  end
192
214
  end
@@ -8,6 +8,8 @@ module Rack::Reqorder::Models
8
8
  field :line, type: Integer
9
9
  field :filepath, type: String
10
10
 
11
+ field :last_seen_at, type: Time
12
+
11
13
  field :resolved, type: Boolean, default: false
12
14
 
13
15
  field :environment, type: String
@@ -18,7 +20,9 @@ module Rack::Reqorder::Models
18
20
 
19
21
  def update_count!
20
22
  self.app_exceptions_count = self.app_exceptions.count
23
+ self.last_seen_at = DateTime.now
21
24
  self.save!
22
25
  end
26
+
23
27
  end
24
28
  end
@@ -23,11 +23,17 @@ module Rack::Reqorder::Models
23
23
  has_one :app_exception, dependent: :destroy
24
24
 
25
25
  belongs_to :route_path, dependent: :nullify
26
+ belongs_to :recording, dependent: :nullify
26
27
 
27
28
  before_create :add_param_keys
29
+ after_save :update_recording_requests_count, if: :recording_id
28
30
  private
29
31
  def add_param_keys
30
32
  self.param_keys = self.params.keys
31
33
  end
34
+
35
+ def update_recording_requests_count
36
+ self.recording.update_requests_count!
37
+ end
32
38
  end
33
39
  end
@@ -6,10 +6,12 @@ module Rack::Reqorder::Models
6
6
 
7
7
  field :headers, type: Hash
8
8
  field :status, type: Integer
9
- #field :body, type: String
9
+ field :body, type: String
10
+ field :length, type: Integer
10
11
  field :response_time, type: Float
11
12
 
12
13
  belongs_to :http_request, dependent: :nullify
14
+ belongs_to :recording, dependent: :nullify
13
15
 
14
16
  before_create :set_response_time
15
17
  after_create :set_response_time_to_request
@@ -0,0 +1,22 @@
1
+ module Rack::Reqorder::Models
2
+ class Recording
3
+ include ::Mongoid::Document
4
+ include ::Kaminari::MongoidExtension::Document
5
+ include ::Mongoid::Timestamps
6
+
7
+ field :http_header, type: String
8
+ field :http_header_value, type: String
9
+ field :enabled, type: Boolean, default: true
10
+ field :requests_count, type: Integer, default: 0
11
+
12
+ has_many :http_requests, dependent: :nullify
13
+ has_many :http_responses, dependent: :nullify
14
+
15
+ scope :enabled, -> {where(enabled: true)}
16
+
17
+ def update_requests_count!
18
+ self.requests_count = self.http_requests.count
19
+ self.save!
20
+ end
21
+ end
22
+ end
@@ -24,11 +24,14 @@ module Rack::Reqorder::Monitor
24
24
  format :json
25
25
  prefix :api
26
26
 
27
- =begin
28
27
  rescue_from Grape::Exceptions::ValidationErrors do |e|
29
28
  error!({errors: e.send(:full_messages)}, 422)
30
29
  end
31
- =end
30
+
31
+ before do
32
+ header 'Access-Control-Allow-Origin', '*'
33
+ header 'Access-Control-Allow-Methods', '*'
34
+ end
32
35
 
33
36
  #collection routes
34
37
  resource :route_paths do
@@ -50,6 +53,15 @@ module Rack::Reqorder::Monitor
50
53
  )
51
54
  end
52
55
 
56
+ delete do
57
+ route_paths = RoutePath.delete_all
58
+
59
+ present_with_meta(
60
+ route_paths,
61
+ present(route_paths, with: RoutePathEntity)
62
+ )
63
+ end
64
+
53
65
  #element routes
54
66
  route_param :id do
55
67
  get do
@@ -89,6 +101,15 @@ module Rack::Reqorder::Monitor
89
101
  )
90
102
  end
91
103
 
104
+ delete do
105
+ requests = HttpRequest.delete_all
106
+
107
+ present_with_meta(
108
+ requests,
109
+ present(requests, with: RequestEntity)
110
+ )
111
+ end
112
+
92
113
  #element routes
93
114
  route_param :id do
94
115
  get do
@@ -119,6 +140,15 @@ module Rack::Reqorder::Monitor
119
140
  )
120
141
  end
121
142
 
143
+ delete do
144
+ responses = HttpResponse.delete_all
145
+
146
+ present_with_meta(
147
+ responses,
148
+ present(responses, with: ResponseEntity)
149
+ )
150
+ end
151
+
122
152
  #element routes
123
153
  route_param :id do
124
154
  get do
@@ -151,6 +181,16 @@ module Rack::Reqorder::Monitor
151
181
  )
152
182
  end
153
183
 
184
+ delete do
185
+ faults = AppFault.delete_all
186
+
187
+ present_with_meta(
188
+ faults,
189
+ present(faults, with: FaultEntity)
190
+ )
191
+
192
+ end
193
+
154
194
  #element routes
155
195
  route_param :id do
156
196
  get do
@@ -194,6 +234,15 @@ module Rack::Reqorder::Monitor
194
234
  )
195
235
  end
196
236
 
237
+ delete do
238
+ exceptions = AppException.delete_all
239
+
240
+ present_with_meta(
241
+ exceptions,
242
+ present(exceptions, with: ExceptionEntity)
243
+ )
244
+ end
245
+
197
246
  #element routes
198
247
  route_param :id do
199
248
  get do
@@ -202,6 +251,56 @@ module Rack::Reqorder::Monitor
202
251
  end
203
252
  end
204
253
 
254
+ #collection routes
255
+ resource :recordings do
256
+ before do
257
+ authorize_user!(headers) unless Rack::Reqorder.configuration.no_auth
258
+ end
259
+
260
+ get do
261
+ recordings = apply_filters(Recording.all, params)
262
+
263
+ meta_aggregations = aggregations(recordings, params)
264
+
265
+ recordings = paginate(recordings, params)
266
+
267
+ present_with_meta(
268
+ recordings,
269
+ present(recordings, with: RecordingEntity),
270
+ meta_aggregations
271
+ )
272
+ end
273
+
274
+ params do
275
+ requires :recording, type: Hash do
276
+ requires :http_header, type: String
277
+ requires :http_header_value, type: String
278
+ end
279
+ end
280
+ post do
281
+ present(
282
+ Recording.create!({
283
+ http_header: declared(params)[:recording][:http_header],
284
+ http_header_value: declared(params)[:recording][:http_header_value]
285
+ }),
286
+ with: RecordingEntity
287
+ )
288
+ end
289
+
290
+ #element routes
291
+ route_param :id do
292
+ get do
293
+ present(Recording.find(params[:id]), with: RecordingEntity)
294
+ end
295
+
296
+ delete do
297
+ recording = Recording.find(params[:id])
298
+ recording.destroy
299
+
300
+ present(recording, with: RecordingEntity)
301
+ end
302
+ end
303
+ end
205
304
 
206
305
  params do
207
306
  requires :user, type: Hash do
@@ -124,6 +124,7 @@ module Rack::Reqorder::Monitor
124
124
 
125
125
  with_options(format_with: :association_id) do
126
126
  expose :http_response, as: :response_id
127
+ expose :recording, as: :recording_id
127
128
  end
128
129
 
129
130
  end
@@ -133,6 +134,7 @@ module Rack::Reqorder::Monitor
133
134
 
134
135
  expose :headers
135
136
  expose :status
137
+ expose :body
136
138
  expose :response_time
137
139
 
138
140
  with_options(format_with: :iso_timestamp) do
@@ -142,6 +144,7 @@ module Rack::Reqorder::Monitor
142
144
 
143
145
  with_options(format_with: :association_id) do
144
146
  expose :http_request, as: :request_id
147
+ expose :recording, as: :recording_id
145
148
  end
146
149
  end
147
150
 
@@ -163,6 +166,7 @@ module Rack::Reqorder::Monitor
163
166
  end
164
167
 
165
168
  with_options(format_with: :iso_timestamp) do
169
+ expose :last_seen_at
166
170
  expose :created_at
167
171
  expose :updated_at
168
172
  end
@@ -187,7 +191,20 @@ module Rack::Reqorder::Monitor
187
191
  expose :http_request, as: :request_id
188
192
  expose :app_fault, as: :fault_id
189
193
  end
194
+ end
195
+
196
+ class RecordingEntity < BaseEntity
197
+ root :recordings, :recording
190
198
 
199
+ expose :http_header
200
+ expose :http_header_value
201
+ expose :enabled
202
+ expose :requests_count
203
+
204
+ with_options(format_with: :iso_timestamp) do
205
+ expose :created_at
206
+ expose :updated_at
207
+ end
191
208
  end
192
209
 
193
210
  class SessionEntity < Grape::Entity
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  module Reqorder
3
- VERSION = "0.4.8"
3
+ VERSION = "0.5"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-reqorder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8
4
+ version: '0.5'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Filippos Vasilakis
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-27 00:00:00.000000000 Z
12
+ date: 2016-04-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -218,6 +218,7 @@ files:
218
218
  - lib/rack/reqorder/models/app_fault.rb
219
219
  - lib/rack/reqorder/models/http_request.rb
220
220
  - lib/rack/reqorder/models/http_response.rb
221
+ - lib/rack/reqorder/models/recording.rb
221
222
  - lib/rack/reqorder/models/route_path.rb
222
223
  - lib/rack/reqorder/models/statistic.rb
223
224
  - lib/rack/reqorder/monitor.rb
@@ -226,7 +227,6 @@ files:
226
227
  - lib/rack/reqorder/route_recognizers.rb
227
228
  - lib/rack/reqorder/services/backtrace_cleaner.rb
228
229
  - lib/rack/reqorder/tasks/routes.rake
229
- - lib/rack/reqorder/tasks/test_database.rake
230
230
  - lib/rack/reqorder/version.rb
231
231
  - rack-reqorder.gemspec
232
232
  homepage: https://github.com/kollegorna/rack-reqorder
@@ -1,29 +0,0 @@
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