rack-profiler 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +79 -12
- data/lib/rack/profiler.rb +53 -52
- data/lib/rack/profiler/version.rb +1 -1
- data/public/rack-profiler.html +15 -7
- data/rack-profiler.gemspec +1 -0
- data/spec/rack/profiler_spec.rb +179 -46
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 10111d8a7faa32f82444b864868a3364a4c557b3
|
4
|
+
data.tar.gz: b77adab1e71c584c5075da95b8eb60f737c84d79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3306764da5aa9f681a1025ce5a0c43ea7cd08d210b8813e0a8e9ff7ab93ab7551ffdf11305479a28f7889e2641a0207170e32ed21e84b6c27117580529494514
|
7
|
+
data.tar.gz: 0647b6ba8a86a09f3d45e2d71c3c71164d494637364cdfdb8af90865ab1a488affc1fe115c9d2530f39f18af3ae53e638bf9b15f3a3e950a594a9d4d8d290fde
|
data/README.md
CHANGED
@@ -1,6 +1,21 @@
|
|
1
1
|
# Rack::Profiler
|
2
2
|
|
3
|
-
Simple profiler for Rack applications
|
3
|
+
Simple profiler for Rack applications (Sinatra and Ruby on Rails for example).
|
4
|
+
|
5
|
+
`Rack::Profiler` uses the [Active Support Instrumentation API](http://guides.rubyonrails.org/active_support_instrumentation.html)
|
6
|
+
and subscribes to the following hooks:
|
7
|
+
|
8
|
+
* [sql.active_record](http://guides.rubyonrails.org/active_support_instrumentation.html#sql-active-record)
|
9
|
+
* [render_template.action_view](http://guides.rubyonrails.org/active_support_instrumentation.html#render_template.action_view)
|
10
|
+
* [render_partial.action_view](http://guides.rubyonrails.org/active_support_instrumentation.html#render_partial.action_view)
|
11
|
+
* [process_action.action_controller](http://guides.rubyonrails.org/active_support_instrumentation.html#process_action.action_controller)
|
12
|
+
|
13
|
+
You can also define your own events, by wrapping your code with the
|
14
|
+
[`Rack::Profiler.step`](#custom-steps).
|
15
|
+
|
16
|
+
`Rack::Profiler` is easy to integrate in any Rack application and it produces a
|
17
|
+
JSON response with the results. It also exposes a simple web dashboard to directly
|
18
|
+
issue HTTP requests to your application and see the results of the profiling.
|
4
19
|
|
5
20
|
## Installation
|
6
21
|
|
@@ -10,6 +25,8 @@ Add this line to your application's Gemfile:
|
|
10
25
|
gem 'rack-profiler'
|
11
26
|
```
|
12
27
|
|
28
|
+
*You might want to put the gem in the development group if you are using Rails.*
|
29
|
+
|
13
30
|
And then execute:
|
14
31
|
|
15
32
|
$ bundle
|
@@ -18,7 +35,7 @@ Or install it yourself as:
|
|
18
35
|
|
19
36
|
$ gem install rack-profiler
|
20
37
|
|
21
|
-
|
38
|
+
### Rack/Sinatra
|
22
39
|
|
23
40
|
In your `config.ru` use the `Rack::Profiler` middleware at the beginning of your
|
24
41
|
middleware stack:
|
@@ -28,21 +45,31 @@ require 'rack/profiler'
|
|
28
45
|
use Rack::Profiler
|
29
46
|
```
|
30
47
|
|
31
|
-
|
32
|
-
|
48
|
+
### Rails
|
49
|
+
|
50
|
+
You can add the `Rack::Profiler` middleware at the beginning of your `config.ru`
|
51
|
+
like in the Rack/Sinatra installation or insert it in the middlewares stack configuration
|
52
|
+
in the `application.rb`:
|
33
53
|
|
34
54
|
```ruby
|
35
|
-
|
36
|
-
|
55
|
+
module YourApp
|
56
|
+
class Application < Rails::Application
|
57
|
+
|
58
|
+
# ...
|
59
|
+
config.middleware.insert_before Rack::Runtime, Rack::Profiler
|
60
|
+
|
61
|
+
end
|
37
62
|
end
|
38
63
|
```
|
39
64
|
|
40
|
-
|
65
|
+
## Configuration
|
66
|
+
|
67
|
+
You can configure `Rack::Profiler` to subscribe to more notifications:
|
41
68
|
|
42
69
|
```ruby
|
43
|
-
Rack::Profiler.configure do |
|
44
|
-
# Subscribe to
|
45
|
-
|
70
|
+
Rack::Profiler.configure do |config|
|
71
|
+
# Subscribe to email delivery in a Rails app
|
72
|
+
config.subscribe('deliver.action_mailer')
|
46
73
|
end
|
47
74
|
```
|
48
75
|
|
@@ -50,12 +77,52 @@ You can also specify a backtrace filter to exclude lines that are not
|
|
50
77
|
interesting:
|
51
78
|
|
52
79
|
```ruby
|
53
|
-
Rack::Profiler.configure do |
|
80
|
+
Rack::Profiler.configure do |config|
|
54
81
|
# Exclude gems from the backtrace
|
55
|
-
|
82
|
+
config.filter_backtrace { |line| !line.include? '/gems/' }
|
56
83
|
end
|
57
84
|
```
|
58
85
|
|
86
|
+
You can put these configurations in your `config.ru` for a Rack/Sinatra application
|
87
|
+
or in an initializer `config/rack_profiler.rb` for Rails apps.
|
88
|
+
|
89
|
+
## Usage
|
90
|
+
|
91
|
+
### Custom steps
|
92
|
+
|
93
|
+
By default `Rack::Profiler` will subscribe to `ActiveRecord` SQL queries,
|
94
|
+
`ActionView` rendering events (templates and partials), `ActionController`
|
95
|
+
actions and to steps you define in your code with:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
Rack::Profiler.step('your-step-name') do
|
99
|
+
# Do stuff. The profiler will tell you how long it took to perform this step
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
103
|
+
### Web Dashboard
|
104
|
+
|
105
|
+
A graphical interface to profile your application pages/endpoints and display the
|
106
|
+
results is automatically mounted at this route:
|
107
|
+
|
108
|
+
http://<your-app-url>/rack-profiler
|
109
|
+
|
110
|
+
Just select the HTTP verb, insert the relative path to your app and add some
|
111
|
+
optional parameters like POST/PUT data: `Rack::Profiler` automatically send
|
112
|
+
the request to your app with the `rack-profiler` param and display the
|
113
|
+
results in a nice graphical way.
|
114
|
+
|
115
|
+
|
116
|
+
### Raw JSON result
|
117
|
+
|
118
|
+
If you want to access the results of the profiling as raw JSON data, you can just
|
119
|
+
add the `rack-profiler` parameter (it can be null) to any HTTP request
|
120
|
+
to your app (GET, POST, PUT, PATCH, DELETE): `Rack::Profiler` will execute the
|
121
|
+
request and return a JSON response containing the results along with the
|
122
|
+
original response.
|
123
|
+
|
124
|
+
http://<your-app-url>/<path>?rack-profiler
|
125
|
+
|
59
126
|
## Contributing
|
60
127
|
|
61
128
|
1. Fork it ( https://github.com/dawanda/rack-profiler/fork )
|
data/lib/rack/profiler.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "rack"
|
2
|
+
require "rack/request"
|
1
3
|
require "rack/profiler/version"
|
2
4
|
require "active_support/notifications"
|
3
5
|
|
@@ -6,22 +8,12 @@ module Rack
|
|
6
8
|
class DummyError < StandardError; end
|
7
9
|
|
8
10
|
module ClassMethods
|
9
|
-
attr_reader :backtrace_filter
|
10
|
-
|
11
11
|
def configure(&block)
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def filter_backtrace(&block)
|
16
|
-
@backtrace_filter = block
|
12
|
+
block.call(config)
|
17
13
|
end
|
18
14
|
|
19
|
-
def
|
20
|
-
@
|
21
|
-
end
|
22
|
-
|
23
|
-
def dashboard_path
|
24
|
-
@dashboard_path || '/rack-profiler'
|
15
|
+
def config
|
16
|
+
@config ||= Configuration.new
|
25
17
|
end
|
26
18
|
|
27
19
|
def step(name, payload = {})
|
@@ -29,37 +21,42 @@ module Rack
|
|
29
21
|
yield
|
30
22
|
end
|
31
23
|
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Configuration
|
27
|
+
attr_reader :subscriptions, :backtrace_filter
|
28
|
+
attr_accessor :dashboard_path
|
29
|
+
|
30
|
+
DEFAULT_SUBSCRIPTIONS = ['sql.active_record',
|
31
|
+
'render_template.action_view',
|
32
|
+
'render_partial.action_view',
|
33
|
+
'process_action.action_controller',
|
34
|
+
'rack-profiler.total_time',
|
35
|
+
'rack-profiler.step']
|
32
36
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
[200, { 'Content-Type' => 'text/html' }, body]
|
37
|
+
def initialize
|
38
|
+
@subscriptions = DEFAULT_SUBSCRIPTIONS.clone
|
39
|
+
@dashboard_path = '/rack-profiler'
|
37
40
|
end
|
38
41
|
|
39
|
-
def subscribe(
|
40
|
-
|
42
|
+
def subscribe(*names)
|
43
|
+
names.each { |name| @subscriptions << name }
|
41
44
|
@subscriptions.uniq!
|
42
45
|
end
|
43
46
|
|
44
|
-
def
|
45
|
-
@
|
47
|
+
def filter_backtrace(&block)
|
48
|
+
@backtrace_filter = block
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
52
|
extend ClassMethods
|
50
53
|
|
51
|
-
# Subscribe to interesting events
|
52
|
-
subscribe('sql.active_record')
|
53
|
-
subscribe('render_template.action_view')
|
54
|
-
subscribe('render_partial.action_view')
|
55
|
-
subscribe('process_action.action_controller')
|
56
|
-
subscribe('rack-profiler.step')
|
57
|
-
|
58
54
|
attr_reader :events
|
59
55
|
|
60
56
|
def initialize(app)
|
61
|
-
|
62
|
-
@
|
57
|
+
subscribe_to_all
|
58
|
+
@events = []
|
59
|
+
@app = app
|
63
60
|
end
|
64
61
|
|
65
62
|
def call(env)
|
@@ -67,13 +64,22 @@ module Rack
|
|
67
64
|
status, headers, body = [nil, nil, nil]
|
68
65
|
req = Rack::Request.new(env)
|
69
66
|
|
70
|
-
if req.path ==
|
71
|
-
|
67
|
+
if req.path == config.dashboard_path
|
68
|
+
render_dashboard
|
72
69
|
elsif req.params.has_key?('rack-profiler')
|
73
|
-
|
70
|
+
ActiveSupport::Notifications.instrument('rack-profiler.total_time') do
|
74
71
|
status, headers, body = @app.call(env)
|
75
72
|
end
|
76
|
-
[200,
|
73
|
+
[ 200,
|
74
|
+
{ 'Content-Type' => 'application/json' },
|
75
|
+
[ { events: events.sort_by { |event| event[:start] },
|
76
|
+
response: {
|
77
|
+
status: status,
|
78
|
+
headers: headers,
|
79
|
+
body: stringify_body(body)
|
80
|
+
}
|
81
|
+
}.to_json ]
|
82
|
+
]
|
77
83
|
else
|
78
84
|
@status, @headers, @body = @app.call(env)
|
79
85
|
end
|
@@ -95,28 +101,23 @@ module Rack
|
|
95
101
|
end
|
96
102
|
end
|
97
103
|
|
98
|
-
def
|
99
|
-
|
100
|
-
nest_event(list, list, evt)
|
101
|
-
end
|
104
|
+
def config
|
105
|
+
self.class.config
|
102
106
|
end
|
103
107
|
|
104
108
|
private
|
105
109
|
|
106
|
-
def
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
+
def render_dashboard
|
111
|
+
dashboard = ::File.expand_path( '../../public/rack-profiler.html', ::File.dirname( __FILE__ ) )
|
112
|
+
body = ::File.open(dashboard, ::File::RDONLY)
|
113
|
+
[200, { 'Content-Type' => 'text/html' }, body]
|
110
114
|
end
|
111
115
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
else
|
117
|
-
children << evt
|
116
|
+
def subscribe_to_all
|
117
|
+
# Subscribe to interesting events
|
118
|
+
config.subscriptions.each do |event|
|
119
|
+
subscribe(event)
|
118
120
|
end
|
119
|
-
list
|
120
121
|
end
|
121
122
|
|
122
123
|
def tap_backtrace
|
@@ -128,17 +129,17 @@ module Rack
|
|
128
129
|
end
|
129
130
|
|
130
131
|
def filtered_backtrace(backtrace)
|
131
|
-
if
|
132
|
+
if config.backtrace_filter.nil?
|
132
133
|
backtrace
|
133
134
|
else
|
134
|
-
backtrace.select(&
|
135
|
+
backtrace.select(&config.backtrace_filter)
|
135
136
|
end
|
136
137
|
end
|
137
138
|
|
138
139
|
def stringify_body(body)
|
139
140
|
body.close if body.respond_to?(:close)
|
140
141
|
str = ""
|
141
|
-
body.each {|part| str << part }
|
142
|
+
body.each { |part| str << part }
|
142
143
|
str
|
143
144
|
end
|
144
145
|
end
|
data/public/rack-profiler.html
CHANGED
@@ -16,6 +16,9 @@
|
|
16
16
|
.response-info {
|
17
17
|
margin-bottom: 1em;
|
18
18
|
}
|
19
|
+
.response-info pre {
|
20
|
+
max-height: 350px;
|
21
|
+
}
|
19
22
|
|
20
23
|
.pr-steps td:first-child {
|
21
24
|
width: 800px;
|
@@ -23,7 +26,7 @@
|
|
23
26
|
|
24
27
|
.step-bar {
|
25
28
|
display: inline-block;
|
26
|
-
background: #
|
29
|
+
background: #777;
|
27
30
|
position: relative;
|
28
31
|
box-sizing: border-box;
|
29
32
|
margin-top: 0.2em;
|
@@ -31,6 +34,10 @@
|
|
31
34
|
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15)
|
32
35
|
}
|
33
36
|
|
37
|
+
.step-bar.step-type-step {
|
38
|
+
background: #5bc0de;
|
39
|
+
}
|
40
|
+
|
34
41
|
.step-bar.step-type-sql {
|
35
42
|
background: #f0ad4e;
|
36
43
|
}
|
@@ -51,6 +58,7 @@
|
|
51
58
|
background-color: #f5f5f5;
|
52
59
|
border: 1px solid #ccc;
|
53
60
|
border-radius: 4px;
|
61
|
+
overflow-wrap: break-word;
|
54
62
|
}
|
55
63
|
|
56
64
|
.key-value-list li {
|
@@ -237,8 +245,11 @@
|
|
237
245
|
.done(function( data, status, xhr ) {
|
238
246
|
$(".stats").show()
|
239
247
|
|
240
|
-
var rootEvent
|
241
|
-
|
248
|
+
var rootEvent = data.events.filter(function(event) {
|
249
|
+
return event.name == 'rack-profiler.total_time'
|
250
|
+
})[0]
|
251
|
+
|
252
|
+
var queryCount = 0,
|
242
253
|
headersKeyVal = exposeKeyValues( data.response.headers ),
|
243
254
|
responseWrap = $.extend( {}, data.response, { headers: headersKeyVal } )
|
244
255
|
|
@@ -270,6 +281,7 @@
|
|
270
281
|
case 'render_template.action_view': eventType = 'render-template'; break;
|
271
282
|
case 'process_action.action_controller': eventType = 'process-action'; break;
|
272
283
|
case 'rack-profiler.step': eventType = 'step'; break;
|
284
|
+
case 'rack-profiler.total_time': eventType = 'total-time'; break;
|
273
285
|
default: eventType = 'other'
|
274
286
|
}
|
275
287
|
|
@@ -285,10 +297,6 @@
|
|
285
297
|
}
|
286
298
|
$(".pr-steps tbody").append( Mustache.render( stepTmpl, stepEvent ) )
|
287
299
|
|
288
|
-
// Recurse on children
|
289
|
-
if ( event.children ) {
|
290
|
-
renderEvents( event.children )
|
291
|
-
}
|
292
300
|
})
|
293
301
|
}
|
294
302
|
|
data/rack-profiler.gemspec
CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency "rack"
|
21
22
|
spec.add_dependency "activesupport", ">= 3.0.0"
|
22
23
|
|
23
24
|
spec.add_development_dependency "bundler", "~> 1.7"
|
data/spec/rack/profiler_spec.rb
CHANGED
@@ -1,55 +1,50 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
def trigger_dummy_event(name, payload = {})
|
5
|
+
ActiveSupport::Notifications.instrument(name, payload) do
|
6
|
+
"do stuff"
|
7
|
+
end
|
8
|
+
end
|
2
9
|
|
3
10
|
describe Rack::Profiler do
|
4
11
|
let(:profiler) { Rack::Profiler.new(nil) }
|
5
12
|
|
6
|
-
|
7
|
-
|
8
|
-
"do stuff"
|
9
|
-
end
|
13
|
+
it "has a version number" do
|
14
|
+
expect(Rack::Profiler::VERSION).not_to be_nil
|
10
15
|
end
|
11
16
|
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
describe :initialize do
|
18
|
+
it "subscribes to all subscriptions" do
|
19
|
+
config = Rack::Profiler::Configuration.new
|
20
|
+
config.subscribe("bar")
|
21
|
+
allow(Rack::Profiler).to receive(:config).and_return(config)
|
15
22
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
evt2 = { start: 2, finish: 3 }
|
20
|
-
evt3 = { start: 4, finish: 8 }
|
21
|
-
evt4 = { start: 5, finish: 8 }
|
22
|
-
evt5 = { start: 9, finish: 10 }
|
23
|
-
evts = [evt1, evt2, evt3, evt4, evt5]
|
24
|
-
allow(profiler).to receive(:events).and_return(evts)
|
25
|
-
nested = profiler.nested_events
|
26
|
-
expect(nested.first).to be(evt1)
|
27
|
-
expect(evt1[:children].first).to be(evt2)
|
28
|
-
expect(evt1[:children][1]).to be(evt3)
|
29
|
-
expect(evt3[:children].first).to be(evt4)
|
30
|
-
expect(evt1[:children].last).to be(evt5)
|
23
|
+
profiler = Rack::Profiler.new(nil)
|
24
|
+
trigger_dummy_event("bar")
|
25
|
+
expect(profiler.events.last[:name]).to eq("bar")
|
31
26
|
end
|
32
27
|
end
|
33
28
|
|
34
29
|
describe :subscribe do
|
35
30
|
before do
|
36
|
-
profiler.subscribe(
|
31
|
+
profiler.subscribe("foo")
|
37
32
|
end
|
38
33
|
|
39
|
-
it "
|
40
|
-
trigger_dummy_event(
|
34
|
+
it "subscribes to event populating the event list" do
|
35
|
+
trigger_dummy_event("foo")
|
41
36
|
event = profiler.events.last
|
42
|
-
expect(event[:name]).to eq(
|
37
|
+
expect(event[:name]).to eq("foo")
|
43
38
|
end
|
44
39
|
|
45
|
-
it "
|
46
|
-
trigger_dummy_event(
|
40
|
+
it "populates event with the proper keys" do
|
41
|
+
trigger_dummy_event("foo")
|
47
42
|
event = profiler.events.last
|
48
43
|
expect(event.keys).to include(:id, :name, :start, :finish, :duration, :payload, :backtrace)
|
49
44
|
end
|
50
45
|
|
51
46
|
it "adds the backtrace" do
|
52
|
-
trigger_dummy_event(
|
47
|
+
trigger_dummy_event("foo")
|
53
48
|
event = profiler.events.last
|
54
49
|
expect(event[:backtrace].any? do |line|
|
55
50
|
line.include?("trigger_dummy_event")
|
@@ -57,10 +52,10 @@ describe Rack::Profiler do
|
|
57
52
|
end
|
58
53
|
|
59
54
|
it "filters the backtrace if a filter was provided" do
|
60
|
-
Rack::Profiler.filter_backtrace do |line|
|
55
|
+
Rack::Profiler.config.filter_backtrace do |line|
|
61
56
|
!line.include?("trigger_dummy_event")
|
62
57
|
end
|
63
|
-
trigger_dummy_event(
|
58
|
+
trigger_dummy_event("foo")
|
64
59
|
event = profiler.events.last
|
65
60
|
expect(event[:backtrace].any? do |line|
|
66
61
|
line.include?("trigger_dummy_event")
|
@@ -71,37 +66,175 @@ describe Rack::Profiler do
|
|
71
66
|
end
|
72
67
|
|
73
68
|
it "adds the payload" do
|
74
|
-
trigger_dummy_event(
|
69
|
+
trigger_dummy_event("foo", bar: "baz")
|
75
70
|
event = profiler.events.last
|
76
|
-
expect(event[:payload]).to eq(bar:
|
71
|
+
expect(event[:payload]).to eq(bar: "baz")
|
77
72
|
end
|
78
73
|
end
|
79
74
|
|
80
|
-
describe
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
75
|
+
describe :call do
|
76
|
+
let(:app) do
|
77
|
+
Proc.new { |env|
|
78
|
+
Rack::Profiler.step 'foo' do
|
79
|
+
[200, { 'X-My-Header' => 'foo' }, ['hello hello']]
|
80
|
+
end
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
let(:profiler) do
|
85
|
+
Rack::Profiler.new(app)
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:env) do
|
89
|
+
{
|
90
|
+
"PATH_INFO" => "/",
|
91
|
+
"QUERY_STRING" => "",
|
92
|
+
"REMOTE_HOST" => "localhost",
|
93
|
+
"REQUEST_METHOD" => "GET",
|
94
|
+
"REQUEST_URI" => "http://localhost:3000/",
|
95
|
+
"SCRIPT_NAME" => "",
|
96
|
+
"SERVER_NAME" => "localhost",
|
97
|
+
"SERVER_PORT" => "3000",
|
98
|
+
"SERVER_PROTOCOL" => "HTTP/1.1",
|
99
|
+
"HTTP_HOST" => "localhost:3000",
|
100
|
+
"rack.version" => [1, 2],
|
101
|
+
"rack.input" => StringIO.new,
|
102
|
+
"rack.errors" => StringIO.new,
|
103
|
+
"rack.multithread" => true,
|
104
|
+
"rack.multiprocess" => false,
|
105
|
+
"rack.run_once" => false,
|
106
|
+
"rack.url_scheme" => "http",
|
107
|
+
"HTTP_VERSION" => "HTTP/1.1",
|
108
|
+
"REQUEST_PATH" => "/"
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
it "clears events" do
|
113
|
+
profiler.events << 'xxx'
|
114
|
+
profiler.call(env)
|
115
|
+
expect(profiler.events).not_to include('xxx')
|
116
|
+
end
|
117
|
+
|
118
|
+
context "when the path is config.dashboard_path" do
|
119
|
+
it "renders dashboard" do
|
120
|
+
expect(profiler).to receive(:render_dashboard)
|
121
|
+
profiler.call env.merge(
|
122
|
+
"PATH_INFO" => profiler.config.dashboard_path,
|
123
|
+
"REQUEST_PATH" => profiler.config.dashboard_path
|
124
|
+
)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when the rack-profiler parameter is not present" do
|
129
|
+
it "transparently returns the original response" do
|
130
|
+
expect(profiler.call(env)).to eq(app.call(env))
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when the rack-profiler parameter is present" do
|
135
|
+
let(:env_with_param) {
|
136
|
+
env.merge('QUERY_STRING' => 'rack-profiler')
|
137
|
+
}
|
138
|
+
|
139
|
+
it "returns a JSON response" do
|
140
|
+
status, headers, body = profiler.call(env_with_param)
|
141
|
+
expect(headers).to match('Content-Type' => 'application/json')
|
142
|
+
expect { JSON.parse(body.join) }.not_to raise_error
|
143
|
+
end
|
144
|
+
|
145
|
+
it "puts the original response in the JSON payload" do
|
146
|
+
status, headers, body = profiler.call(env_with_param)
|
147
|
+
parsed_body = JSON.parse(body.join)
|
148
|
+
expect(parsed_body['response']).to eq(
|
149
|
+
'status' => 200,
|
150
|
+
'headers' => { 'X-My-Header' => 'foo' },
|
151
|
+
'body' => 'hello hello'
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
it "puts the received events in the JSON payload" do
|
156
|
+
status, headers, body = profiler.call(env_with_param)
|
157
|
+
parsed_body = JSON.parse(body.join)
|
158
|
+
expect(
|
159
|
+
parsed_body['events'].map { |e| e['name'] }
|
160
|
+
).to include('rack-profiler.total_time', 'rack-profiler.step')
|
161
|
+
end
|
87
162
|
end
|
88
163
|
end
|
89
164
|
|
90
165
|
describe ".step" do
|
91
|
-
it "calls ActiveSupport::Notifications.instrument with the right
|
166
|
+
it "calls ActiveSupport::Notifications.instrument with the right args" do
|
92
167
|
expect(ActiveSupport::Notifications).to receive(:instrument).with(
|
93
|
-
|
94
|
-
Rack::Profiler.step(
|
168
|
+
"rack-profiler.step", { step_name: "xxx" })
|
169
|
+
Rack::Profiler.step("xxx") do
|
95
170
|
"do stuff"
|
96
171
|
end
|
97
172
|
end
|
98
173
|
|
99
174
|
it "mixes data in the payload if provided" do
|
100
175
|
expect(ActiveSupport::Notifications).to receive(:instrument).with(
|
101
|
-
|
102
|
-
Rack::Profiler.step(
|
176
|
+
"rack-profiler.step", { step_name: "xxx", foo: "bar" })
|
177
|
+
Rack::Profiler.step("xxx", foo: "bar") do
|
103
178
|
"do stuff"
|
104
179
|
end
|
105
180
|
end
|
106
181
|
end
|
182
|
+
|
183
|
+
describe ".configure" do
|
184
|
+
it "executes the given block passing the configuration object" do
|
185
|
+
config_inside_block = nil
|
186
|
+
Rack::Profiler.configure do |c|
|
187
|
+
config_inside_block = c
|
188
|
+
end
|
189
|
+
expect(config_inside_block).to be(Rack::Profiler.config)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe ".config" do
|
194
|
+
it "instantiates a Configuration object if there is none" do
|
195
|
+
Rack::Profiler.send(:instance_variable_set, :@config, nil)
|
196
|
+
expect(Rack::Profiler.config).to be_a(Rack::Profiler::Configuration)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe Rack::Profiler::Configuration do
|
202
|
+
let(:config) { Rack::Profiler::Configuration.new }
|
203
|
+
|
204
|
+
it "has the correct defaults" do
|
205
|
+
expect(config.dashboard_path).to eq('/rack-profiler')
|
206
|
+
expect(config.backtrace_filter).to be_nil
|
207
|
+
expect(config.subscriptions).to include(
|
208
|
+
*Rack::Profiler::Configuration::DEFAULT_SUBSCRIPTIONS
|
209
|
+
)
|
210
|
+
end
|
211
|
+
|
212
|
+
describe :subscribe do
|
213
|
+
it "adds entries to subscriptions" do
|
214
|
+
config.subscribe('bar')
|
215
|
+
expect(config.subscriptions).to include('bar')
|
216
|
+
end
|
217
|
+
|
218
|
+
it "accepts more than one subscription" do
|
219
|
+
config.subscribe('bar', 'baz')
|
220
|
+
expect(config.subscriptions).to include('bar', 'baz')
|
221
|
+
end
|
222
|
+
|
223
|
+
it "does not add duplicates" do
|
224
|
+
config.subscribe('bar', 'bar')
|
225
|
+
expect(
|
226
|
+
config.subscriptions.count { |s| s == 'bar' }
|
227
|
+
).to eq(1)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe :filter_backtrace do
|
232
|
+
it "sets the backtrace_filter" do
|
233
|
+
config.filter_backtrace do |line|
|
234
|
+
line.include? 'foo'
|
235
|
+
end
|
236
|
+
filtered = ['foo', 'foobar', 'baz'].select(&config.backtrace_filter)
|
237
|
+
expect(filtered).to eq(['foo', 'foobar'])
|
238
|
+
end
|
239
|
+
end
|
107
240
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-profiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Ongaro
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-01-
|
12
|
+
date: 2015-01-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rack
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: activesupport
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|