rack-profiler 0.0.3 → 0.0.4
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.
- 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
|