methodmissing-scrooge 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +227 -22
- data/VERSION.yml +1 -1
- data/assets/config/scrooge.yml.template +6 -0
- data/lib/scrooge/framework/base.rb +26 -15
- data/lib/scrooge/framework/rails.rb +28 -4
- data/lib/scrooge/middleware/tracker.rb +0 -1
- data/lib/scrooge/orm/active_record.rb +7 -3
- data/lib/scrooge/profile.rb +72 -73
- data/lib/scrooge/strategy/base.rb +74 -0
- data/lib/scrooge/strategy/controller.rb +29 -0
- data/lib/scrooge/strategy/scope.rb +14 -0
- data/lib/scrooge/strategy/stage.rb +77 -0
- data/lib/scrooge/strategy/track.rb +19 -0
- data/lib/scrooge/strategy/track_then_scope.rb +41 -0
- data/lib/scrooge/tracker/app.rb +63 -3
- data/lib/scrooge/tracker/base.rb +10 -0
- data/lib/scrooge/tracker/model.rb +7 -0
- data/lib/scrooge/tracker/resource.rb +17 -2
- data/lib/scrooge.rb +2 -1
- data/rails/init.rb +1 -1
- data/spec/fixtures/config/scrooge.yml +5 -1
- data/spec/units/scrooge/framework/base_spec.rb +9 -3
- data/spec/units/scrooge/profile_spec.rb +13 -15
- data/spec/units/scrooge/strategy/base_spec.rb +62 -0
- data/spec/units/scrooge/strategy/controller_spec.rb +26 -0
- data/spec/units/scrooge/strategy/scope_spec.rb +18 -0
- data/spec/units/scrooge/strategy/stage_spec.rb +35 -0
- data/spec/units/scrooge/strategy/track_spec.rb +19 -0
- data/spec/units/scrooge/strategy/track_then_scope_spec.rb +22 -0
- data/spec/units/scrooge/tracker/app_spec.rb +5 -1
- data/spec/units/scrooge/tracker/base_spec.rb +8 -0
- data/spec/units/scrooge/tracker/model_spec.rb +14 -1
- data/spec/units/scrooge/tracker/resource_spec.rb +21 -0
- data/tasks/scrooge.rake +1 -1
- metadata +16 -2
data/README.textile
CHANGED
@@ -14,11 +14,15 @@ h2. Why bother ?
|
|
14
14
|
|
15
15
|
h2. Suggested Use
|
16
16
|
|
17
|
-
|
17
|
+
There's 3 basic modes of operation :
|
18
18
|
|
19
|
-
|
19
|
+
* Track : Track attribute access to dump a representative scope profile.
|
20
20
|
|
21
|
-
|
21
|
+
* Scope : Scope the process and related resources to a previously persisted scope profile.
|
22
|
+
|
23
|
+
* Track then scope : A multi-stage strategy that tracks attribute access for
|
24
|
+
|
25
|
+
h2. Resources
|
22
26
|
|
23
27
|
A resource is :
|
24
28
|
|
@@ -28,24 +32,23 @@ A resource is :
|
|
28
32
|
|
29
33
|
All Model to attribute mappings is tracked on a per Resource basis.Multiple Models per Resource is supported.
|
30
34
|
|
35
|
+
h2. Strategies
|
36
|
+
|
31
37
|
h4. Tracking
|
32
38
|
|
33
|
-
In tracking mode
|
39
|
+
In tracking mode Scrooge installs filters ( either through Rack middleware or framework specific hooks ) that track attribute access on a per Resource basis.
|
34
40
|
|
35
41
|
A Kernel#at_exit callback dumps and timestamps this profile ( or scope ) to eg. *framework_configuration_directory/config/scopes/1234147851/scope.yml*
|
36
42
|
|
37
|
-
This typically
|
43
|
+
This typically works well with functional or integration testing and can yield a substantial birds eye view of attribute
|
44
|
+
use.The accuracy is directly proportional to test coverage and the quality of the test suite.
|
38
45
|
|
39
|
-
|
46
|
+
Example log output :
|
40
47
|
|
41
48
|
<pre>
|
42
49
|
<code>
|
43
50
|
Processing HotelsController#index (for 0.0.0.0 at 2009-02-09 02:55:55) [GET]
|
44
51
|
Parameters: {"action"=>"index", "controller"=>"hotels"}
|
45
|
-
[Scrooge] Track with resource #< :/ ()
|
46
|
-
[Scrooge] Track for Resource #<GET :hotels/index (*/*)
|
47
|
-
- #<Hotel :from_price, :narrative, :star_rating, :latitude, :created_at, :hotel_name, :updated_at, :important_notes, :id, :apt, :location_id, :nearest_tube, :longitude, :telephone, :nearest_rail, :location_name, :distance>
|
48
|
-
- #<Image :thumbnail_width, :created_at, :title, :updated_at, :url, :thumbnail_height, :height, :thumbnail_url, :has_thumbnail, :hotel_id, :width>
|
49
52
|
Hotel Load (0.3ms) SELECT * FROM `hotels` LIMIT 0, 15
|
50
53
|
Rendering template within layouts/application
|
51
54
|
Rendering hotels/index
|
@@ -154,20 +157,18 @@ An example scope / profile, saved to disk :
|
|
154
157
|
</code>
|
155
158
|
</pre>
|
156
159
|
|
157
|
-
h4.
|
160
|
+
h4. Scope
|
158
161
|
|
159
162
|
A previously persisted scope / profile can be restored from disk and injected to the applicable Resources.Database content retrieved will match that of the given scope timestamp.
|
160
163
|
|
161
|
-
This is typically pushed to production and adjusted for each major release or deployment.
|
164
|
+
This is typically pushed to production where a hybrid ( track then scope strategy) mode of operation is frowned upon and adjusted for each major release or deployment.
|
162
165
|
|
163
|
-
|
166
|
+
Example log output :
|
164
167
|
|
165
168
|
<pre>
|
166
169
|
<code>
|
167
170
|
Processing HotelsController#index (for 0.0.0.0 at 2009-02-09 02:59:41) [GET]
|
168
171
|
Parameters: {"action"=>"index", "controller"=>"hotels"}
|
169
|
-
[Scrooge] Scope for Model #<Image :created_at, :thumbnail_width, :title, :updated_at, :url, :id, :thumbnail_height, :height, :thumbnail_url, :has_thumbnail, :width, :hotel_id>
|
170
|
-
[Scrooge] Scope for Model #<Hotel :narrative, :from_price, :created_at, :latitude, :star_rating, :hotel_name, :updated_at, :important_notes, :apt, :id, :nearest_tube, :location_id, :nearest_rail, :telephone, :longitude, :distance, :location_name>
|
171
172
|
Hotel Load (0.4ms) SELECT hotels.narrative, hotels.from_price, hotels.created_at, hotels.latitude, hotels.star_rating, hotels.hotel_name, hotels.updated_at, hotels.important_notes, hotels.apt, hotels.id, hotels.nearest_tube, hotels.location_id, hotels.nearest_rail, hotels.telephone, hotels.longitude, hotels.distance, hotels.location_name FROM `hotels` LIMIT 0, 15
|
172
173
|
Rendering template within layouts/application
|
173
174
|
Rendering hotels/index
|
@@ -184,6 +185,164 @@ Log output may look like :
|
|
184
185
|
</code>
|
185
186
|
</pre>
|
186
187
|
|
188
|
+
h4. Track then scope
|
189
|
+
|
190
|
+
Multi-stage and self configuring strategy that tracks attribute access for a given warmup period, synchronize the results across n-1 processes, aggregate the results to be representative of the whole cluster ( or seamless fallback to a single process ), remove the tracking filters and install functionality that scopes database access to that of the tracking phase.
|
191
|
+
|
192
|
+
Recommended for production use.
|
193
|
+
|
194
|
+
Example log output :
|
195
|
+
|
196
|
+
<pre>
|
197
|
+
<code>
|
198
|
+
Processing HotelsController#index (for 127.0.0.1 at 2009-02-16 00:00:58) [GET]
|
199
|
+
Parameters: {"action"=>"index", "controller"=>"hotels"}
|
200
|
+
Hotel Load (0.5ms) SELECT * FROM `hotels` LIMIT 0, 15
|
201
|
+
Hotel Columns (7.7ms) SHOW FIELDS FROM `hotels`
|
202
|
+
SQL (3.9ms) SELECT count(*) AS count_all FROM `hotels`
|
203
|
+
Rendering template within layouts/application
|
204
|
+
Rendering hotels/index
|
205
|
+
Image Load (0.5ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11381) LIMIT 1
|
206
|
+
Image Columns (3.6ms) SHOW FIELDS FROM `images`
|
207
|
+
Rendered hotels/_hotel (200.2ms)
|
208
|
+
Image Load (0.4ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11382) LIMIT 1
|
209
|
+
Rendered hotels/_hotel (2.4ms)
|
210
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11697) LIMIT 1
|
211
|
+
Rendered hotels/_hotel (1.8ms)
|
212
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12693) LIMIT 1
|
213
|
+
Rendered hotels/_hotel (1.7ms)
|
214
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12738) LIMIT 1
|
215
|
+
Rendered hotels/_hotel (1.6ms)
|
216
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12886) LIMIT 1
|
217
|
+
Rendered hotels/_hotel (1.9ms)
|
218
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13007) LIMIT 1
|
219
|
+
Rendered hotels/_hotel (1.8ms)
|
220
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13074) LIMIT 1
|
221
|
+
Rendered hotels/_hotel (1.5ms)
|
222
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13077) LIMIT 1
|
223
|
+
Rendered hotels/_hotel (1.6ms)
|
224
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13078) LIMIT 1
|
225
|
+
Rendered hotels/_hotel (1.8ms)
|
226
|
+
Image Load (0.3ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13079) LIMIT 1
|
227
|
+
Rendered hotels/_hotel (2.4ms)
|
228
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13080) LIMIT 1
|
229
|
+
Rendered hotels/_hotel (1.8ms)
|
230
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13082) LIMIT 1
|
231
|
+
Rendered hotels/_hotel (1.5ms)
|
232
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13085) LIMIT 1
|
233
|
+
Rendered hotels/_hotel (1.8ms)
|
234
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13105) LIMIT 1
|
235
|
+
Rendered hotels/_hotel (1.6ms)
|
236
|
+
Rendered shared/_header (0.4ms)
|
237
|
+
Rendered shared/_navigation (0.8ms)
|
238
|
+
Missing template hotels/_index_sidebar.erb in view path app/views
|
239
|
+
Rendered shared/_sidebar (0.4ms)
|
240
|
+
Rendered shared/_footer (0.3ms)
|
241
|
+
Completed in 270ms (View: 243, DB: 20) | 200 OK [http://localhost/hotels]
|
242
|
+
[Scrooge] Execute stage :synchronize ...
|
243
|
+
[Scrooge] Uninstalling tracking middleware ...
|
244
|
+
[Scrooge] Stop tracking ...
|
245
|
+
[Scrooge] Synchronize results with other processes ...
|
246
|
+
Cache write: 17619400_63223_756033
|
247
|
+
Cache read: scrooge_tracker_aggregation
|
248
|
+
Cache write: scrooge_tracker_aggregation
|
249
|
+
[Scrooge] Execute stage :aggregate ...
|
250
|
+
[Scrooge] Aggregate results from other processes ...
|
251
|
+
|
252
|
+
|
253
|
+
Processing HotelsController#index (for 127.0.0.1 at 2009-02-16 00:01:37) [GET]
|
254
|
+
Parameters: {"action"=>"index", "controller"=>"hotels"}
|
255
|
+
Hotel Load (0.5ms) SELECT * FROM `hotels` LIMIT 0, 15
|
256
|
+
SQL (0.2ms) SELECT count(*) AS count_all FROM `hotels`
|
257
|
+
Rendering template within layouts/application
|
258
|
+
Rendering hotels/index
|
259
|
+
Image Load (0.3ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11381) LIMIT 1
|
260
|
+
Rendered hotels/_hotel (2.0ms)
|
261
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11382) LIMIT 1
|
262
|
+
Rendered hotels/_hotel (1.8ms)
|
263
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 11697) LIMIT 1
|
264
|
+
Rendered hotels/_hotel (1.7ms)
|
265
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12693) LIMIT 1
|
266
|
+
Rendered hotels/_hotel (1.6ms)
|
267
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12738) LIMIT 1
|
268
|
+
Rendered hotels/_hotel (1.5ms)
|
269
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 12886) LIMIT 1
|
270
|
+
Rendered hotels/_hotel (1.8ms)
|
271
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13007) LIMIT 1
|
272
|
+
Rendered hotels/_hotel (1.8ms)
|
273
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13074) LIMIT 1
|
274
|
+
Rendered hotels/_hotel (1.4ms)
|
275
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13077) LIMIT 1
|
276
|
+
Rendered hotels/_hotel (1.6ms)
|
277
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13078) LIMIT 1
|
278
|
+
Rendered hotels/_hotel (1.6ms)
|
279
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13079) LIMIT 1
|
280
|
+
Rendered hotels/_hotel (1.8ms)
|
281
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13080) LIMIT 1
|
282
|
+
Rendered hotels/_hotel (1.7ms)
|
283
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13082) LIMIT 1
|
284
|
+
Rendered hotels/_hotel (1.5ms)
|
285
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13085) LIMIT 1
|
286
|
+
Rendered hotels/_hotel (1.7ms)
|
287
|
+
Image Load (0.2ms) SELECT * FROM `images` WHERE (`images`.hotel_id = 13105) LIMIT 1
|
288
|
+
Rendered hotels/_hotel (81.1ms)
|
289
|
+
Rendered shared/_header (0.1ms)
|
290
|
+
Rendered shared/_navigation (0.3ms)
|
291
|
+
Missing template hotels/_index_sidebar.erb in view path app/views
|
292
|
+
Rendered shared/_sidebar (0.1ms)
|
293
|
+
Rendered shared/_footer (0.1ms)
|
294
|
+
Completed in 113ms (View: 107, DB: 4) | 200 OK [http://localhost/hotels]
|
295
|
+
Cache read: scrooge_tracker_aggregation
|
296
|
+
Cache read: 17619400_63223_756033
|
297
|
+
[Scrooge] Execute stage :scope ...
|
298
|
+
[Scrooge] Scope ...
|
299
|
+
|
300
|
+
|
301
|
+
Processing HotelsController#index (for 127.0.0.1 at 2009-02-16 00:01:53) [GET]
|
302
|
+
Parameters: {"action"=>"index", "controller"=>"hotels"}
|
303
|
+
Hotel Load (0.7ms) SELECT hotels.narrative, hotels.from_price, hotels.created_at, hotels.latitude, hotels.star_rating, hotels.hotel_name, hotels.updated_at, hotels.important_notes, hotels.apt, hotels.id, hotels.nearest_tube, hotels.location_id, hotels.nearest_rail, hotels.telephone, hotels.longitude, hotels.distance, hotels.location_name FROM `hotels` LIMIT 0, 15
|
304
|
+
SQL (0.2ms) SELECT count(*) AS count_all FROM `hotels`
|
305
|
+
Rendering template within layouts/application
|
306
|
+
Rendering hotels/index
|
307
|
+
Image Load (0.3ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 11381) LIMIT 1
|
308
|
+
Rendered hotels/_hotel (2.0ms)
|
309
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 11382) LIMIT 1
|
310
|
+
Rendered hotels/_hotel (1.7ms)
|
311
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 11697) LIMIT 1
|
312
|
+
Rendered hotels/_hotel (1.7ms)
|
313
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 12693) LIMIT 1
|
314
|
+
Rendered hotels/_hotel (1.7ms)
|
315
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 12738) LIMIT 1
|
316
|
+
Rendered hotels/_hotel (1.5ms)
|
317
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 12886) LIMIT 1
|
318
|
+
Rendered hotels/_hotel (1.7ms)
|
319
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13007) LIMIT 1
|
320
|
+
Rendered hotels/_hotel (1.8ms)
|
321
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13074) LIMIT 1
|
322
|
+
Rendered hotels/_hotel (1.4ms)
|
323
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13077) LIMIT 1
|
324
|
+
Rendered hotels/_hotel (1.5ms)
|
325
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13078) LIMIT 1
|
326
|
+
Rendered hotels/_hotel (1.8ms)
|
327
|
+
Image Load (0.3ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13079) LIMIT 1
|
328
|
+
Rendered hotels/_hotel (1.9ms)
|
329
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13080) LIMIT 1
|
330
|
+
Rendered hotels/_hotel (1.7ms)
|
331
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13082) LIMIT 1
|
332
|
+
Rendered hotels/_hotel (1.5ms)
|
333
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13085) LIMIT 1
|
334
|
+
Rendered hotels/_hotel (1.7ms)
|
335
|
+
Image Load (0.2ms) SELECT images.created_at, images.thumbnail_width, images.title, images.updated_at, images.url, images.id, images.thumbnail_height, images.height, images.thumbnail_url, images.has_thumbnail, images.width, images.hotel_id FROM `images` WHERE (`images`.hotel_id = 13105) LIMIT 1
|
336
|
+
Rendered hotels/_hotel (1.7ms)
|
337
|
+
Rendered shared/_header (0.1ms)
|
338
|
+
Rendered shared/_navigation (0.2ms)
|
339
|
+
Missing template hotels/_index_sidebar.erb in view path app/views
|
340
|
+
Rendered shared/_sidebar (0.0ms)
|
341
|
+
Rendered shared/_footer (0.0ms)
|
342
|
+
Completed in 34ms (View: 27, DB: 4) | 200 OK [http://localhost/hotels]
|
343
|
+
</code>
|
344
|
+
</pre>
|
345
|
+
|
187
346
|
h2. Installation
|
188
347
|
|
189
348
|
h4. As a Rails plugin ( Recommended )
|
@@ -203,24 +362,34 @@ h2. Configuration
|
|
203
362
|
|
204
363
|
Scrooge installs ( see recommended installation above ) a configuration file with the following format within *framework_configuration_directory/scrooge.yml ( RAILS_ROOT/config/scrooge.yml for a Rails setup ) :
|
205
364
|
|
365
|
+
<pre>
|
366
|
+
<code>
|
206
367
|
production:
|
207
368
|
orm: :active_record
|
208
369
|
storage: :memory
|
370
|
+
strategy: :track_then_scope
|
371
|
+
warmup: 600 # warmup / track for 10 minutes
|
209
372
|
scope:
|
210
373
|
on_missing_attribute: :reload # or :raise
|
211
|
-
enabled: true
|
212
|
-
|
374
|
+
enabled: true
|
375
|
+
development:
|
213
376
|
orm: :active_record
|
214
377
|
storage: :memory
|
378
|
+
strategy: :track
|
379
|
+
warmup: 600 # warmup / track for 10 minutes
|
215
380
|
scope:
|
216
381
|
on_missing_attribute: :reload # or :raise
|
217
382
|
enabled: true
|
218
383
|
test:
|
219
384
|
orm: :active_record
|
220
385
|
storage: :memory
|
386
|
+
strategy: :track
|
387
|
+
warmup: 600 # warmup / track for 10 minutes
|
221
388
|
scope:
|
222
389
|
on_missing_attribute: :reload # or :raise
|
223
|
-
enabled: true
|
390
|
+
enabled: true
|
391
|
+
</code>
|
392
|
+
</pre>
|
224
393
|
|
225
394
|
h4. ORM
|
226
395
|
|
@@ -234,6 +403,14 @@ Tracking results can be persisted to a given backend or storage option.Ships wit
|
|
234
403
|
|
235
404
|
storage: :memory
|
236
405
|
|
406
|
+
h4. Strategy
|
407
|
+
|
408
|
+
One of :track, :scope or :track_then_scope .Only the :track_then_scope strategy respects the :warmup configuration option.
|
409
|
+
|
410
|
+
h4. Warmup
|
411
|
+
|
412
|
+
The designated warmup period for the :track_then_scope strategy, given in seconds.Typically 600 to 3600.
|
413
|
+
|
237
414
|
h4. Scope
|
238
415
|
|
239
416
|
A scope is a reference to a timestamped Scrooge run where access to Model attributes is tracked on a per Resource basis.
|
@@ -254,9 +431,37 @@ Scrooge can be disabled with :
|
|
254
431
|
|
255
432
|
enabled: false
|
256
433
|
|
257
|
-
h2.
|
434
|
+
h2. Rails specific rake tasks.
|
435
|
+
|
436
|
+
Ships with tasks to assist in inspecting results.
|
258
437
|
|
259
|
-
|
438
|
+
<pre>
|
439
|
+
<code>
|
440
|
+
methodmissing:superbreak_app lourens$ rake scrooge:list
|
441
|
+
(in /Users/lourens/projects/superbreak_app)
|
442
|
+
- 1234735663
|
443
|
+
- 1234735722
|
444
|
+
- 1234735744
|
445
|
+
- 1234735790
|
446
|
+
- 1234738880
|
447
|
+
methodmissing:superbreak_app lourens$ rake scope=1234735790 scrooge:inspect
|
448
|
+
(in /Users/lourens/projects/superbreak_app)
|
449
|
+
#<GET :hotels/show (*/*)
|
450
|
+
- #<Hotel :important_notes, :location_id>
|
451
|
+
- #<Address :line1, :created_at, :line2, :postcode, :updated_at, :country_id, :county, :location_id, :town, :hotel_id>
|
452
|
+
|
453
|
+
#<GET :countries/index (*/*)
|
454
|
+
- #<Country :name, :created_at, :code, :updated_at, :id, :location_id, :continent_id>
|
455
|
+
|
456
|
+
#<GET :locations/index (*/*)
|
457
|
+
- #<Location :name, :created_at, :code, :updated_at, :level, :id>
|
458
|
+
|
459
|
+
#<GET :hotels/index (*/*)
|
460
|
+
- #<Image :created_at, :thumbnail_width, :title, :updated_at, :url, :thumbnail_height, :height, :thumbnail_url, :has_thumbnail, :width, :hotel_id>
|
461
|
+
- #<Hotel :narrative, :from_price, :created_at, :latitude, :star_rating, :hotel_name, :updated_at, :important_notes, :apt, :id, :nearest_tube, :location_id, :nearest_rail, :telephone, :longitude, :distance, :location_name>
|
462
|
+
</code>
|
463
|
+
</pre>
|
464
|
+
|
465
|
+
h2. Notes
|
260
466
|
|
261
|
-
|
262
|
-
and on the fly scope injection after a given warmup threshold but found that to be overkill for a first release.
|
467
|
+
This is an initial release, has not yet been battle tested in production and is pending Ruby 1.9.1 compatibility.
|
data/VERSION.yml
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
production:
|
2
2
|
orm: :active_record
|
3
3
|
storage: :memory
|
4
|
+
strategy: :track_then_scope
|
5
|
+
warmup: 600 # warmup / track for 10 minutes
|
4
6
|
scope:
|
5
7
|
on_missing_attribute: :reload # or :raise
|
6
8
|
enabled: true
|
7
9
|
development:
|
8
10
|
orm: :active_record
|
9
11
|
storage: :memory
|
12
|
+
strategy: :track
|
13
|
+
warmup: 600 # warmup / track for 10 minutes
|
10
14
|
scope:
|
11
15
|
on_missing_attribute: :reload # or :raise
|
12
16
|
enabled: true
|
13
17
|
test:
|
14
18
|
orm: :active_record
|
15
19
|
storage: :memory
|
20
|
+
strategy: :track
|
21
|
+
warmup: 600 # warmup / track for 10 minutes
|
16
22
|
scope:
|
17
23
|
on_missing_attribute: :reload # or :raise
|
18
24
|
enabled: true
|
@@ -50,27 +50,27 @@ module Scrooge
|
|
50
50
|
class InvalidScopeSignature < StandardError
|
51
51
|
end
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
53
|
+
# Per framework signature lookup.
|
54
|
+
#
|
55
|
+
@@signatures = Hash.new( [] )
|
56
|
+
@@signatures[self.name] = []
|
57
|
+
|
58
|
+
# Support none by default.
|
59
|
+
#
|
60
|
+
@@frameworks = []
|
61
|
+
|
62
|
+
class << self
|
63
63
|
|
64
64
|
# Registers a framework signature.
|
65
65
|
#
|
66
66
|
def signature( &block )
|
67
|
-
@@signatures[self.name]
|
67
|
+
@@signatures[self.name] << block
|
68
68
|
end
|
69
69
|
|
70
70
|
# All signatures for the current klass.
|
71
71
|
#
|
72
72
|
def signatures
|
73
|
-
@@signatures[self.name]
|
73
|
+
@@signatures[self.name]
|
74
74
|
end
|
75
75
|
|
76
76
|
# All supported frameworks.
|
@@ -173,6 +173,12 @@ module Scrooge
|
|
173
173
|
raise NotImplemented
|
174
174
|
end
|
175
175
|
|
176
|
+
# Remove tracking middleware
|
177
|
+
#
|
178
|
+
def uninstall_tracking_middleware
|
179
|
+
raise NotImplemented
|
180
|
+
end
|
181
|
+
|
176
182
|
# Register a code block to run when the host framework is fully initialized.
|
177
183
|
#
|
178
184
|
def initialized( &block )
|
@@ -202,7 +208,7 @@ module Scrooge
|
|
202
208
|
# Return the scopes storage path for the current framework.
|
203
209
|
#
|
204
210
|
def scopes_path
|
205
|
-
@
|
211
|
+
@scopes_path ||= File.join( config, 'scrooge', 'scopes' )
|
206
212
|
end
|
207
213
|
|
208
214
|
# Return the scopes storage path for a given scope and optional filename.
|
@@ -214,8 +220,9 @@ module Scrooge
|
|
214
220
|
|
215
221
|
# Log a message to the logger.
|
216
222
|
#
|
217
|
-
def log( message )
|
223
|
+
def log( message, flush = false )
|
218
224
|
logger.info "[Scrooge] #{message}"
|
225
|
+
flush_logger! if flush
|
219
226
|
end
|
220
227
|
|
221
228
|
# Persist the current tracker as scope or restore a previously persisted scope
|
@@ -251,7 +258,7 @@ module Scrooge
|
|
251
258
|
GUARD.synchronize do
|
252
259
|
scope = Time.now.to_i
|
253
260
|
dump_scope!( scope )
|
254
|
-
scope
|
261
|
+
scope.to_s
|
255
262
|
end
|
256
263
|
end
|
257
264
|
|
@@ -263,6 +270,10 @@ module Scrooge
|
|
263
270
|
|
264
271
|
private
|
265
272
|
|
273
|
+
def flush_logger! #:nodoc:
|
274
|
+
logger.flush if logger.respond_to?(:flush)
|
275
|
+
end
|
276
|
+
|
266
277
|
def restore_scope!( scope ) #:nodoc:
|
267
278
|
tracker = Scrooge::Tracker::App.new
|
268
279
|
tracker.marshal_load( scope_from_yaml( scope ) )
|
@@ -57,21 +57,31 @@ module Scrooge
|
|
57
57
|
#
|
58
58
|
def install_tracking_middleware
|
59
59
|
GUARD.synchronize do
|
60
|
-
|
60
|
+
with_or_without_prepatation( :scrooge_install_tracking_middleware ) do
|
61
61
|
ApplicationController.prepend_around_filter Scrooge::Middleware::Tracker
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
# Remove all tracking filters
|
67
|
+
#
|
68
|
+
def uninstall_tracking_middleware
|
69
|
+
GUARD.synchronize do
|
70
|
+
# Handle dev. mode
|
71
|
+
ActionController::Dispatcher.prepare_dispatch_callback_chain.delete( :scrooge_install_tracking_middleware )
|
72
|
+
ApplicationController.skip_filter Scrooge::Middleware::Tracker
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
66
76
|
# Install per Resource scoping middleware.
|
67
77
|
#
|
68
78
|
def install_scope_middleware( tracker )
|
69
79
|
GUARD.synchronize do
|
70
|
-
|
80
|
+
with_or_without_prepatation( :scrooge_install_scope_middleware ) do
|
71
81
|
tracker.resources.each do |resource|
|
72
82
|
install_scope_middleware_for_resource!( resource )
|
73
83
|
end
|
74
|
-
|
84
|
+
end
|
75
85
|
end
|
76
86
|
end
|
77
87
|
|
@@ -79,7 +89,7 @@ module Scrooge
|
|
79
89
|
begin
|
80
90
|
::Rails.configuration.after_initialize( &block )
|
81
91
|
rescue NameError
|
82
|
-
# No
|
92
|
+
# No config initialized - plugin installation etc.
|
83
93
|
end
|
84
94
|
end
|
85
95
|
|
@@ -89,6 +99,20 @@ module Scrooge
|
|
89
99
|
|
90
100
|
private
|
91
101
|
|
102
|
+
def with_or_without_prepatation( callback_signature, &block ) #:nodoc:
|
103
|
+
if development?
|
104
|
+
ActionController::Dispatcher.to_prepare( callback_signature ) do
|
105
|
+
block.call
|
106
|
+
end
|
107
|
+
else
|
108
|
+
block.call
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def development? #:nodoc:
|
113
|
+
environment == 'development'
|
114
|
+
end
|
115
|
+
|
92
116
|
def install_scope_middleware_for_resource!( resource ) #:nodoc:
|
93
117
|
resource.middleware.each do |resource_middleware|
|
94
118
|
controller( resource ).prepend_around_filter resource_middleware, :only => resource.action
|
@@ -12,7 +12,6 @@ module Scrooge
|
|
12
12
|
Scrooge::Base.profile.tracker.track( Thread.scrooge_resource ) do
|
13
13
|
begin
|
14
14
|
Scrooge::Base.profile.framework.resource( {}, controller.request )
|
15
|
-
Scrooge::Base.profile.log "Track for Resource #{Thread.scrooge_resource.inspect}"
|
16
15
|
block.call
|
17
16
|
ensure
|
18
17
|
Thread.reset_scrooge_resource!
|
@@ -28,7 +28,6 @@ module Scrooge
|
|
28
28
|
|
29
29
|
def register_with_scrooge!( attr_name, caller ) #:nodoc:
|
30
30
|
if ::Scrooge::Base.profile.orm.track?
|
31
|
-
logger.info "[Scrooge] #{caller} #{attr_name.to_s}"
|
32
31
|
Thread.scrooge_resource << [self.base_class, attr_name]
|
33
32
|
end
|
34
33
|
end
|
@@ -55,7 +54,6 @@ module Scrooge
|
|
55
54
|
|
56
55
|
def register_with_scrooge!( attr_name, caller ) #:nodoc:
|
57
56
|
if ::Scrooge::Base.profile.orm.track?
|
58
|
-
logger.info "[Scrooge] #{caller} #{attr_name.to_s}"
|
59
57
|
Thread.scrooge_resource << [self.class.base_class, attr_name]
|
60
58
|
end
|
61
59
|
end
|
@@ -105,7 +103,7 @@ module Scrooge
|
|
105
103
|
#
|
106
104
|
def scope_resource_to_model( resource, model )
|
107
105
|
method_name = resource_scope_method( resource )
|
108
|
-
klass =
|
106
|
+
klass = klass_for_model( model )
|
109
107
|
unless resource_scope_method?( resource, klass )
|
110
108
|
klass.instance_eval(<<-EOS, __FILE__, __LINE__)
|
111
109
|
def #{method_name}(&block)
|
@@ -138,6 +136,12 @@ module Scrooge
|
|
138
136
|
model.primary_key
|
139
137
|
end
|
140
138
|
|
139
|
+
private
|
140
|
+
|
141
|
+
def klass_for_model( model ) #:nodoc:
|
142
|
+
model.model.is_a?(String) ? model.model.to_const!(false) : model.model
|
143
|
+
end
|
144
|
+
|
141
145
|
end
|
142
146
|
end
|
143
147
|
end
|