pilfer 0.0.1.pre4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NzFkODBmMDU3MzMxMmQ2MGRiYjZhMmI2Y2I2OWQ4NmE0YzVlMmJiOQ==
4
+ MWJkZjU3Njk0N2IyMjZiNjJiOTZkMTQ4ZDk4MGQwZWU3MGQ4NGExNQ==
5
5
  data.tar.gz: !binary |-
6
- ZjVlOGMyYWFiNjM5ZWIyODI5NGU5MDI3YWYxZmJmNGM3YzFlNWQ4Nw==
6
+ NmExMWFlYWIwNGU3ZTg5NTk1MWYyMTgxZWJhMmQwNDVhOWIwMDdiMw==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NTI5NjVlNGNlNGU0NzlkNzgwYWI0YTYyMjhmNmMzYWQyOWQwOWFkYmJiN2Ey
10
- NTY4NWUxOTRkOTRjNjlhZjA3ZmEwNWFmOWQ2YmRlYjhmNjEyNjJiMDg2OWY2
11
- NTA0MTZhYWI3YzYzOWE5OWZkODRmMWI4MGI3MjhkYjEwYzk0NGU=
9
+ YWM2ZTNjNmZkYzA5YzlhNDIxM2RiYTA5NTkwOTZkN2VkODBkOGEwN2VmMmM1
10
+ ZjdiYjRjNzhkZWEzYzlmN2MzNmZhZTRiYjUxZjc0NWE2Y2UwMDAwYmViMTgw
11
+ ZjE1NDg3MzM0NzMyMGVjM2NiMGU4OGIxZjU0YTcxMDlhM2Y4NTY=
12
12
  data.tar.gz: !binary |-
13
- YzY3Mzk5N2VlNzBiNzdmMWU2ZDBhNDMxMGEwNDVhODQwMTI1MTRhMWQxODJk
14
- OGM1MDIzYjVlYTVkYTFkYTU5MjMwNzE2ZDA5YjkxNzEzZWU5OWYwYzc5OTU3
15
- OWVhZmQ0YTc5NGNmNTY3MWU0Zjk0ZDc1NDA5ZmVmODg0ZmE4YTU=
13
+ M2RhZDQ5MWFmMmNkYjI5MTM5NzM4ODA1NTFiODUxOTZhMWU5MWYwMmY5YjE0
14
+ NjA5OTE3ZDVlZmUzNWY3NDBhYjkzZmY0Y2NmMTBlYmMwMDY3ZTBiYjlmYmE3
15
+ NTVmNGZiOWE1NWFkYzBjMjQ4ZjFhMGViNDM2ODBiZTY1YjYxZWY=
data/README.md CHANGED
@@ -1,30 +1,94 @@
1
1
  # Pilfer
2
2
 
3
- Look into your ruby with [rblineprof](https://github.com/tmm1/rblineprof/).
3
+ Profile Ruby code and find out _exactly_ how slow it runs.
4
+
5
+ Pilfer uses [rblineprof][] to measure how long each line of code takes to
6
+ execute and the number of times it was called.
7
+
8
+ ![Pilfer Profile.png](http://cl.ly/image/2a1d332M2w05/Pilfer%20Profile.png)
9
+
10
+ Take a look at some [Pilfer profiles of the Bundler API site][bundler-pilfer].
11
+
12
+ ## Installation
13
+
14
+ Using with Bundler is as simple as adding `pilfer` to your `Gemfile`.
15
+
16
+ ```ruby
17
+ gem 'pilfer', '~> 1.0.0'
18
+ ```
19
+
20
+ Or install it locally like any other gem.
21
+
22
+ ```bash
23
+ $ gem install pilfer
24
+ ```
4
25
 
5
26
  ## Usage
6
27
 
7
28
  Profile a block of code saving the report to the file `profile.log`.
8
29
 
30
+ ```ruby
31
+ require 'pilfer'
32
+
33
+ reporter = Pilfer::Logger.new('pilfer.log')
34
+ profiler = Pilfer::Profiler.new(reporter)
35
+ profiler.profile('bubble sorting') do
36
+ array = (0..100).to_a.shuffle
37
+ bubble_sort array
38
+ end
39
+ ```
40
+
41
+ Profile your Rack or Rails app using `Pilfer::Middleware`.
42
+
9
43
  ```ruby
10
44
  reporter = Pilfer::Logger.new('pilfer.log')
11
45
  profiler = Pilfer::Profiler.new(reporter)
12
- profiler.profile { do_something }
46
+ use Pilfer::Middleware :profiler => profiler
13
47
  ```
14
48
 
15
- The report prints the source of each line of code executed and includes the
16
- total execution time and the number of times the line was executed.
49
+ The profile report consists of the wall time and call count for each line of
50
+ code executed along with the total wall and CPU times for each file.
17
51
 
18
- _TODO: Show profile response._
52
+ ```
53
+ Profile start="2013-05-12 00:41:16 UTC" description="bubble sorting"
54
+ /Users/Larry/Sites/pilfer/sort.rb wall_time=42.5ms cpu_time=29.7ms
55
+ | require 'pilfer'
56
+ |
57
+ | def bubble_sort(container)
58
+ 42.5ms ( 1) | loop do
59
+ | swapped = false
60
+ 42.3ms ( 94) | (container.size-1).times do |i|
61
+ 10.2ms ( 9400) | if (container[i] <=> container[i+1]) == 1
62
+ 6.2ms ( 5092) | container[i], container[i+1] = container[i+1], container[i] # Swap
63
+ | swapped = true
64
+ | end
65
+ | end
66
+ | break unless swapped
67
+ | end
68
+ | container
69
+ | end
70
+ |
71
+ | reporter = Pilfer::Logger.new($stdout)
72
+ | profiler = Pilfer::Profiler.new(reporter)
73
+ | profiler.profile_files_matching(/sort\.rb/, 'bubble sorting') do
74
+ 0.1ms ( 3) | array = (0..100).to_a.shuffle
75
+ 42.5ms ( 1) | bubble_sort array
76
+ | end
77
+ ```
19
78
 
20
79
  ### Step 1: Create a reporter
21
80
 
22
- Profiles can be sent to a [pilfer-server][] or written to a file or `IO`
23
- object.
81
+ Decide how you want line profiles to be reported. Profiles can be sent to a
82
+ [pilfer-server][] or written to a file path or `IO` object.
24
83
 
25
84
  ```ruby
26
- reporter = Pilfer::Server.new('https://pilfer.com', 'abc123')
85
+ # Send reports to a pilfer-server
86
+ reporter = Pilfer::Server.new('https://pilfer.com', 'my-pilfer-server-token')
87
+
88
+ # Append reports to a file
27
89
  reporter = Pilfer::Logger.new('pilfer.log')
90
+
91
+ # Print reports to standard out
28
92
  reporter = Pilfer::Logger.new($stdout)
29
93
  ```
30
94
 
@@ -33,12 +97,21 @@ the application root with `:app_root` to have it trimmed from reported file
33
97
  paths.
34
98
 
35
99
  ```ruby
36
- reporter = Pilfer::Logger.new($stdout, :app_root => '/my/app')
100
+ reporter = Pilfer::Logger.new('pilfer.log')
101
+ # Profile start=2013-05-02 14:17:26 UTC
102
+ # /Sites/bundler-api/lib/bundler-api/web.rb wall_time=1009.5ms cpu_time=0.5ms
103
+ # ...
104
+
105
+ reporter = Pilfer::Logger.new('pilfer.log', :app_root => '/Sites/bundler-api/')
106
+ # Profile start=2013-05-02 14:17:26 UTC
107
+ # lib/bundler-api/web.rb wall_time=1009.5ms cpu_time=0.5ms
108
+ # ...
37
109
  ```
38
110
 
39
111
  ### Step 2: Create a profiler
40
112
 
41
- Pass the reporter to a new `Pilfer::Profiler`.
113
+ A `Profiler` runs the line profiler and sends it to a reporter. Create one
114
+ passing the reporter created in the previous step.
42
115
 
43
116
  ```ruby
44
117
  profiler = Pilfer::Profiler.new(reporter)
@@ -46,53 +119,81 @@ profiler = Pilfer::Profiler.new(reporter)
46
119
 
47
120
  ### Step 3: Profile a block of code
48
121
 
49
- Profile a block of code with `#profile`.
122
+ Use `Profiler#profile` to profile a block of code. Optionally, provide a
123
+ description of the code being profiling.
50
124
 
51
125
  ```ruby
52
- profiler.profile { do_something }
126
+ profiler.profile('bubble sorting') do
127
+ array = (0..100).to_a.shuffle
128
+ bubble_sort array
129
+ end
53
130
  ```
54
131
 
55
- Every file that's executed by the block--including code outside the
56
- application like gems and standard libraries--will be included in the profile.
57
- Use `#profile_files_matching` and provide a regular expression to limit
58
- profiling to only matching file paths.
132
+ Every file that's executed by the block including code outside the
133
+ application like gems and standard libraries will be included in the profile.
134
+ Use `#profile_files_matching` to limit profiling to files whose paths match a
135
+ regular expression.
59
136
 
60
137
  ```ruby
138
+ # Only profile Rails models
61
139
  matcher = %r{^#{Regexp.escape(Rails.root.to_s)}/app/models}
62
- profiler.profile_files_matching(matcher) { do_something }
140
+ profiler.profile_files_matching(matcher, 'User.find_by_email') do
141
+ User.find_by_email('arthur@dent.com')
142
+ end
143
+ ```
144
+
145
+ Additional arguments to `#profile` and `#profile_files_matching` will be
146
+ passed to the reporter. The `Pilfer::Server` reporter, for example, can submit
147
+ profiles asynchronously.
148
+
149
+ ```ruby
150
+ profiler.profile('bubble sorting', :submit => :async) do
151
+ array = (0..100).to_a.shuffle
152
+ bubble_sort array
153
+ end
63
154
  ```
64
155
 
65
- ## Pilfer Server
156
+ ## Extras
66
157
 
67
- [pilfer-server][] is your own, personal service for collecting and viewing
68
- profile reports. Follow the [pilfer-server setup instructions][pilfer-server]
69
- to stand up a new server and send it reports using its URL and token.
158
+ ### Pilfer Server
159
+
160
+ [Pilfer Server][pilfer-server] is your own, personal service for collecting
161
+ and viewing line profiles gathered by Pilfer. Follow the
162
+ [Pilfer Server setup instructions][pilfer-server-readme] to stand up a new
163
+ server.
70
164
 
71
165
  ```ruby
72
- reporter = Pilfer::Server.new('https://pilfer.com', 'abc123')
166
+ reporter = Pilfer::Server.new('https://pilfer.com', 'my-pilfer-server-token')
167
+ profiler = Pilfer::Profiler.new(reporter)
168
+ profiler.profile('bubble sorting') do
169
+ array = (0..100).to_a.shuffle
170
+ bubble_sort array
171
+ end
73
172
  ```
74
173
 
75
- ## Rack Middleware
174
+ ### Rack Middleware
76
175
 
77
- Profile your Rack or Rails app using `Pilfer::Middleware`.
176
+ Profile your entire Rack or Rails app using `Pilfer::Middleware`. Pass it a
177
+ `Profiler` created with a reporter as normal.
78
178
 
79
179
  ```ruby
80
- reporter = Pilfer::Logger.new($stdout, :app_root => Rails.root)
180
+ reporter = Pilfer::Server.new('https://pilfer.com', 'my-pilfer-server-token')
81
181
  profiler = Pilfer::Profiler.new(reporter)
82
182
  use Pilfer::Middleware :profiler => profiler
83
183
  ```
84
184
 
85
- Restrict the files profiled by passing a regular expression with
86
- `:files_matching`.
185
+ Restrict profiling to files matching a regular expression using the
186
+ `:files_matching` option. This calls `Profiler#profile_files_matching` using
187
+ the given regular expression.
87
188
 
88
189
  ```ruby
89
190
  matcher = %r{^#{Regexp.escape(Rails.root.to_s)}/(app|config|lib|vendor/plugin)}
90
- use Pilfer::Middleware, :files_matching => matcher,
91
- :profiler => profiler
191
+ use Pilfer::Middleware, :profiler => profiler,
192
+ :files_matching => matcher
92
193
  ```
93
194
 
94
- You probably don't want to profile _every_ request. The given block will be
95
- evaluated on each request to determine if a profile should be run.
195
+ You almost certainly don't want to profile _every_ request. Provide a block to
196
+ determine if a profile should be run on the incoming request.
96
197
 
97
198
  ```ruby
98
199
  use Pilfer::Middleware, :profiler => profiler do
@@ -104,10 +205,39 @@ end
104
205
  The Rack environment is available to allow profiling on demand.
105
206
 
106
207
  ```ruby
208
+ # Profile requests containing the query string ?profile=true
107
209
  use Pilfer::Middleware, :profiler => profiler do |env|
108
210
  env.query_string.include? 'profile=true'
109
211
  end
212
+
213
+ # Profile requests containing a header whose value matches a secret
214
+ use Pilfer::Middleware, :profiler => profiler do |env|
215
+ env['HTTP_PROFILE_AUTHORIZATION'] == 'super-secret'
216
+ end
110
217
  ```
111
218
 
219
+ ## Supported Ruby Versions
220
+
221
+ This library is [tested against][travis] the following Ruby versions.
222
+
223
+ - MRI 1.9.3
224
+ - MRI 1.8.7
225
+ - REE
226
+
227
+ If you need a specific version supported, open and issue or send a pull
228
+ request.
229
+
230
+ ## License
231
+
232
+ The MIT License (MIT)
233
+
234
+ Copyright (c) 2013 Eric Lindvall and Larry Marburger. See [LICENSE][] for
235
+ details.
236
+
112
237
 
113
- [pilfer-server]: https://github.com/eric/pilfer-server
238
+ [rblineprof]: https://github.com/tmm1/rblineprof
239
+ [bundler-pilfer]: https://pilfer.herokuapp.com/dashboard
240
+ [pilfer-server]: https://github.com/eric/pilfer-server
241
+ [pilfer-server-readme]: https://github.com/eric/pilfer-server#readme
242
+ [travis]: https://travis-ci.org/eric/pilfer
243
+ [license]: LICENSE
@@ -0,0 +1,5 @@
1
+ require 'pilfer/logger'
2
+ require 'pilfer/middleware'
3
+ require 'pilfer/profiler'
4
+ require 'pilfer/server'
5
+ require 'pilfer/version'
@@ -13,9 +13,9 @@ module Pilfer
13
13
  end
14
14
  end
15
15
 
16
- def write(profile_data, profile_start)
16
+ def write(profile_data, profile_start, description, options = {})
17
17
  profile = Pilfer::Profile.new(profile_data, profile_start)
18
- print_report_banner profile_start
18
+ print_report_banner profile_start, description
19
19
  profile.each do |path, data|
20
20
  print_file_banner path, data
21
21
  print_file_source_with_profile path, data
@@ -24,9 +24,10 @@ module Pilfer
24
24
 
25
25
  private
26
26
 
27
- def print_report_banner(profile_start)
27
+ def print_report_banner(profile_start, description)
28
28
  formatted_start = profile_start.utc.strftime('%Y-%m-%d %H:%M:%S UTC')
29
- logger.info "Profile start=#{formatted_start}"
29
+ logger.info %{Profile start="#{formatted_start}" } +
30
+ %{description="#{description}"}
30
31
  end
31
32
 
32
33
  def print_file_banner(path, data)
@@ -14,23 +14,28 @@ module Pilfer
14
14
 
15
15
  def call(env)
16
16
  if profile_guard.call(env)
17
- run_profiler { app.call(env) }
17
+ run_profiler(request_description(env)) { app.call(env) }
18
18
  else
19
19
  app.call(env)
20
20
  end
21
21
  end
22
22
 
23
- def run_profiler(&downstream)
23
+ def run_profiler(description, &downstream)
24
24
  if file_matcher
25
- profiler.profile_files_matching(file_matcher, &downstream)
25
+ profiler.profile_files_matching(file_matcher, description,
26
+ :submit => :async, &downstream)
26
27
  else
27
- profiler.profile(&downstream)
28
+ profiler.profile(description, :submit => :async, &downstream)
28
29
  end
29
30
  end
30
31
 
31
32
  def default_profiler
32
- reporter = Pilfer::Logger.new($stdout, :app_root => ENV['PWD'])
33
+ reporter = Pilfer::Logger.new($stdout)
33
34
  Pilfer::Profiler.new(reporter)
34
35
  end
36
+
37
+ def request_description(env)
38
+ "#{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}"
39
+ end
35
40
  end
36
41
  end
@@ -8,17 +8,19 @@ module Pilfer
8
8
  @reporter = reporter
9
9
  end
10
10
 
11
- def profile(profiler = method(:lineprof), start = Time.now, &app)
12
- profile_files_matching(/./, profiler, start, &app)
11
+ def profile(*args, &app)
12
+ profile_files_matching(/./, *args, &app)
13
13
  end
14
14
 
15
- def profile_files_matching(matcher, profiler = method(:lineprof),
15
+ def profile_files_matching(matcher, description = nil,
16
+ reporter_options = {},
17
+ profiler = method(:lineprof),
16
18
  start = Time.now, &app)
17
19
  app_response = nil
18
20
  profile = profiler.call(matcher) do
19
21
  app_response = app.call
20
22
  end
21
- reporter.write profile, start
23
+ reporter.write profile, start, description, reporter_options
22
24
  app_response
23
25
  end
24
26
  end
@@ -0,0 +1,103 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'pilfer/profile'
4
+ require 'uri'
5
+
6
+ module Pilfer
7
+ class Server
8
+ attr_accessor :uri, :token
9
+
10
+ def initialize(uri, token, options = {})
11
+ @uri = URI.parse(uri)
12
+ @token = token
13
+ @async = options[:async] || true
14
+ end
15
+
16
+ def write(profile_data, profile_start, description, options = {})
17
+ async = (options[:submit] || :sync) == :async
18
+ details = { 'hostname' => Socket.gethostname,
19
+ 'pid' => Process.pid,
20
+ 'description' => description,
21
+ 'file_sources' => file_sources_for_profile(profile_data) }
22
+
23
+ payload = RbLineProfFormat.
24
+ profile_to_json(profile_data, profile_start).
25
+ merge(details)
26
+
27
+ if async
28
+ Thread.new(payload) do |payload|
29
+ submit_profile payload
30
+ end
31
+ else
32
+ submit_profile payload
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def submit_profile(payload)
39
+ request = Net::HTTP::Post.new('/api/profiles')
40
+ request.content_type = 'application/json'
41
+ request['Authorization'] = %{Token token="#{token}"}
42
+ request.body = JSON.generate(payload)
43
+
44
+ http = Net::HTTP.new(uri.host, uri.port)
45
+
46
+ if uri.scheme == 'https'
47
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
48
+ http.use_ssl = true
49
+ store = OpenSSL::X509::Store.new
50
+ store.set_default_paths
51
+ http.cert_store = store
52
+ end
53
+
54
+ case (response = http.start {|http| http.request(request) })
55
+ when Net::HTTPSuccess, Net::HTTPRedirection
56
+ else
57
+ response.error!
58
+ end
59
+ rescue Exception => ex
60
+ $stdout.puts ex.message, ex.backtrace
61
+ end
62
+
63
+ def file_sources_for_profile(profile_data)
64
+ profile_data.each_with_object({}) {|(file, _), sources|
65
+ sources[file] = File.exists?(file) ? File.read(file) : nil
66
+ }
67
+ end
68
+ end
69
+ end
70
+
71
+ # Formatting a profile as JSON may eventually be provided by rblineprof.
72
+ class RbLineProfFormat
73
+ def self.profile_to_json(profile_data, profile_start)
74
+ files = profile_data.each_with_object({}) do |(file, lines), files|
75
+ profile_lines = lines[1..-1].
76
+ each_with_index.
77
+ each_with_object({}) do |(data, number), lines|
78
+ next unless data.any? {|datum| datum > 0 }
79
+ wall_time, cpu_time, calls = data
80
+ lines[number] = { 'wall_time' => wall_time,
81
+ 'cpu_time' => cpu_time,
82
+ 'calls' => calls }
83
+ end
84
+
85
+ total, child, exclusive, total_cpu, child_cpu, exclusive_cpu = lines[0]
86
+
87
+ files[file] = { 'total' => total,
88
+ 'child' => child,
89
+ 'exclusive' => exclusive,
90
+ 'total_cpu' => total_cpu,
91
+ 'child_cpu' => child_cpu,
92
+ 'exclusive_cpu' => exclusive_cpu,
93
+ 'lines' => profile_lines }
94
+ end
95
+
96
+ {
97
+ 'profile' => {
98
+ 'timestamp' => profile_start.to_i,
99
+ 'files' => files
100
+ }
101
+ }
102
+ end
103
+ end
@@ -1,3 +1,3 @@
1
1
  module Pilfer
2
- VERSION = '0.0.1.pre4'
2
+ VERSION = '1.0.0'
3
3
  end
@@ -5,12 +5,16 @@ require 'pilfer/version'
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'pilfer'
7
7
  spec.version = Pilfer::VERSION
8
- spec.summary = 'Look into your ruby with rblineprof'
9
8
  spec.authors = ['Eric Lindvall', 'Larry Marburger']
10
9
  spec.email = ['eric@sevenscale.com', 'larry@marburger.cc']
11
10
  spec.homepage = 'https://github.com/eric/pilfer'
12
11
  spec.license = 'MIT'
13
12
 
13
+ spec.summary = 'line-profiler for ruby and rack'
14
+ spec.description = 'pilfer uses rblineprof to measure how long each line ' +
15
+ 'of code takes to execute and the number of times it ' +
16
+ 'was called.'
17
+
14
18
  spec.files = %w(Gemfile LICENSE README.md)
15
19
  spec.files << 'pilfer.gemspec'
16
20
  spec.files += Dir.glob('lib/**/*.rb')
@@ -0,0 +1,45 @@
1
+ require 'helper'
2
+ require 'stringio'
3
+ require 'pilfer'
4
+
5
+ describe Pilfer do
6
+ context 'reporting to a Pilfer::Logger' do
7
+ let(:reporter) { Pilfer::Logger.new(output) }
8
+ let(:output) { StringIO.new }
9
+
10
+ it 'reports profile' do
11
+ Pilfer::Profiler.new(reporter).
12
+ profile_files_matching(/integration_spec\.rb/, "testing") do
13
+ 10.times do
14
+ sleep 0.01
15
+ end
16
+ end
17
+
18
+ lines = output.string.split("\n")
19
+ lines[0].should =~ %r{Profile start="[\d-]{10} [\d:]{8} UTC" description="testing"$}
20
+
21
+ wall_time = lines[1].match(/wall_time=([\d\.]+)/)[1].to_f
22
+ wall_time.should be_within(10).of(105)
23
+ end
24
+
25
+ it 'ignores optional reporter args' do
26
+ Pilfer::Profiler.new(reporter).
27
+ profile_files_matching(/integration_spec\.rb/, "testing",
28
+ :report => :async) do
29
+ 10.times do
30
+ sleep 0.01
31
+ end
32
+ end
33
+
34
+ lines = output.string.split("\n")
35
+ lines[0].should =~ %r{Profile start="[\d-]{10} [\d:]{8} UTC" description="testing"$}
36
+
37
+ wall_time = lines[1].match(/wall_time=([\d\.]+)/)[1].to_f
38
+ wall_time.should be_within(10).of(105)
39
+ end
40
+ end
41
+
42
+ context 'reporting to a Pilfer::Server' do
43
+ it 'reports profile'
44
+ end
45
+ end
@@ -10,9 +10,10 @@ describe Pilfer::Logger do
10
10
  profile_content = File.read(profile_file).gsub('SPEC_ROOT', spec_root)
11
11
  JSON.parse(profile_content)
12
12
  }
13
- let(:reporter) { StringIO.new }
14
- let(:start) { Time.at(42) }
15
- let(:output) {
13
+ let(:description) { "GET /" }
14
+ let(:reporter) { StringIO.new }
15
+ let(:start) { Time.at(42) }
16
+ let(:output) {
16
17
  reporter.string.each_line.map {|line|
17
18
  line.sub(/I, \[[^\]]+\] INFO -- : /, '')
18
19
  }.join
@@ -27,7 +28,7 @@ describe Pilfer::Logger do
27
28
  describe '#write' do
28
29
  it 'writes profile to reporter' do
29
30
  expected = <<-EOS
30
- Profile start=1970-01-01 00:00:42 UTC
31
+ Profile start="1970-01-01 00:00:42 UTC" description="GET /"
31
32
  #{spec_root}/files/hello.rb wall_time=0.0ms cpu_time=0.0ms
32
33
  0.0ms ( 2) | print 'Hello '
33
34
  #{spec_root}/files/test.rb wall_time=113.7ms cpu_time=5.3ms
@@ -49,19 +50,19 @@ Profile start=1970-01-01 00:00:42 UTC
49
50
  | end
50
51
  | end
51
52
  EOS
52
- Pilfer::Logger.new(reporter).write(profile, start)
53
+ Pilfer::Logger.new(reporter).write(profile, start, description)
53
54
  output.should eq(expected)
54
55
  end
55
56
 
56
57
  it 'omits app root' do
57
58
  Pilfer::Logger.new(reporter, :app_root => spec_root).
58
- write(profile, start)
59
+ write(profile, start, description)
59
60
  first_file.should eq('files/hello.rb')
60
61
  end
61
62
 
62
63
  it 'omits app root with trailing separator' do
63
64
  Pilfer::Logger.new(reporter, :app_root => spec_root + '/').
64
- write(profile, start)
65
+ write(profile, start, description)
65
66
  first_file.should eq('files/hello.rb')
66
67
  end
67
68
 
@@ -72,17 +73,25 @@ EOS
72
73
 
73
74
  it 'omits the source of the nonexistent file' do
74
75
  expected = <<-EOS
75
- Profile start=1970-01-01 00:00:42 UTC
76
+ Profile start="1970-01-01 00:00:42 UTC" description="GET /"
76
77
  (eval) wall_time=113.7ms cpu_time=5.3ms
77
78
  EOS
78
- Pilfer::Logger.new(reporter).write(profile, start)
79
+ Pilfer::Logger.new(reporter).write(profile, start, description)
79
80
  output.should eq(expected)
80
81
  end
81
82
  end
82
83
 
83
84
  it 'appends to the log file' do
84
- 3.times { Pilfer::Logger.new(reporter).write(profile, start) }
85
+ 3.times {
86
+ Pilfer::Logger.new(reporter).write(profile, start, description)
87
+ }
85
88
  output.scan('Profile start=').size.should eq(3)
86
89
  end
90
+
91
+ it 'ignores optional options' do
92
+ Pilfer::Logger.new(reporter, :app_root => spec_root).
93
+ write(profile, start, description, :async => false)
94
+ output.should_not be_nil
95
+ end
87
96
  end
88
97
  end
@@ -12,7 +12,8 @@ describe Pilfer::Middleware do
12
12
 
13
13
  it 'profiles and calls the downstream app' do
14
14
  app.should_receive(:call).with(env).once
15
- profiler.should_receive(:profile).with(no_args).and_yield
15
+ profiler.should_receive(:profile).
16
+ with("GET /", :submit => :async).and_yield
16
17
  subject.call(env)
17
18
  end
18
19
 
@@ -33,8 +34,8 @@ describe Pilfer::Middleware do
33
34
 
34
35
  it 'passes file matcher to profiler and calls the downstream app' do
35
36
  app.should_receive(:call).with(env).once
36
- profiler.should_receive(:profile_files_matching).with(file_matcher).
37
- and_yield
37
+ profiler.should_receive(:profile_files_matching).
38
+ with(file_matcher, "GET /", :submit => :async).and_yield
38
39
  subject.call(env)
39
40
  end
40
41
  end
@@ -2,14 +2,17 @@ require 'helper'
2
2
  require 'pilfer/profiler'
3
3
 
4
4
  describe Pilfer::Profiler do
5
- let(:reporter) { stub(:reporter, :write => nil) }
6
- let(:start) { stub(:start) }
5
+ let(:reporter) { stub(:reporter, :write => nil) }
6
+ let(:reporter_options) { stub(:reporter_options) }
7
+ let(:description) { stub(:description) }
8
+ let(:profiler) { stub(:profiler, :call => :profiler_response) }
9
+ let(:start) { stub(:start) }
7
10
 
8
11
  describe '#profile' do
9
12
  it 'profiles all files by default' do
10
- profiler = stub(:profiler)
11
13
  profiler.should_receive(:call).with(/./)
12
- Pilfer::Profiler.new(reporter).profile(profiler) { }
14
+ Pilfer::Profiler.new(reporter).
15
+ profile(description, reporter_options, profiler) { }
13
16
  end
14
17
 
15
18
  it 'returns value of app' do
@@ -18,17 +21,17 @@ describe Pilfer::Profiler do
18
21
  :profiler_response
19
22
  }
20
23
 
21
- response = Pilfer::Profiler.new(reporter).profile(profiler) {
22
- :app_response
23
- }
24
+ response = Pilfer::Profiler.new(reporter).
25
+ profile(description, reporter_options, profiler) { :app_response }
24
26
 
25
27
  response.should eq(:app_response)
26
28
  end
27
29
 
28
30
  it 'writes profile to reporter' do
29
- profiler = stub(:profiler, :call => :profiler_response)
30
- reporter.should_receive(:write).with(:profiler_response, start)
31
- Pilfer::Profiler.new(reporter).profile(profiler, start) { }
31
+ reporter.should_receive(:write).
32
+ with(:profiler_response, start, description, reporter_options)
33
+ Pilfer::Profiler.new(reporter).
34
+ profile(description, reporter_options, profiler, start) { }
32
35
  end
33
36
  end
34
37
 
@@ -36,17 +39,18 @@ describe Pilfer::Profiler do
36
39
  let(:matcher) { stub(:matcher) }
37
40
 
38
41
  it 'passes file matcher to profiler' do
39
- profiler = stub(:profiler)
40
42
  profiler.should_receive(:call).with(matcher)
41
43
  Pilfer::Profiler.new(reporter).
42
- profile_files_matching(matcher, profiler) { }
44
+ profile_files_matching(matcher, description, reporter_options,
45
+ profiler) { }
43
46
  end
44
47
 
45
48
  it 'writes profile to reporter' do
46
- profiler = stub(:profiler, :call => :profiler_response)
47
- reporter.should_receive(:write).with(:profiler_response, start)
49
+ reporter.should_receive(:write).
50
+ with(:profiler_response, start, description, reporter_options)
48
51
  Pilfer::Profiler.new(reporter).
49
- profile_files_matching(matcher, profiler, start) { }
52
+ profile_files_matching(matcher, description, reporter_options,
53
+ profiler, start) { }
50
54
  end
51
55
  end
52
56
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pilfer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre4
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Lindvall
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-22 00:00:00.000000000 Z
12
+ date: 2013-05-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rblineprof
@@ -39,7 +39,8 @@ dependencies:
39
39
  - - ~>
40
40
  - !ruby/object:Gem::Version
41
41
  version: '1.0'
42
- description:
42
+ description: pilfer uses rblineprof to measure how long each line of code takes to
43
+ execute and the number of times it was called.
43
44
  email:
44
45
  - eric@sevenscale.com
45
46
  - larry@marburger.cc
@@ -55,10 +56,13 @@ files:
55
56
  - lib/pilfer/middleware.rb
56
57
  - lib/pilfer/profile.rb
57
58
  - lib/pilfer/profiler.rb
59
+ - lib/pilfer/server.rb
58
60
  - lib/pilfer/version.rb
61
+ - lib/pilfer.rb
59
62
  - spec/files/hello.rb
60
63
  - spec/files/test.rb
61
64
  - spec/helper.rb
65
+ - spec/integration_spec.rb
62
66
  - spec/pilfer/logger_spec.rb
63
67
  - spec/pilfer/middleware_spec.rb
64
68
  - spec/pilfer/profile_spec.rb
@@ -88,11 +92,12 @@ rubyforge_project:
88
92
  rubygems_version: 2.0.3
89
93
  signing_key:
90
94
  specification_version: 4
91
- summary: Look into your ruby with rblineprof
95
+ summary: line-profiler for ruby and rack
92
96
  test_files:
93
97
  - spec/files/hello.rb
94
98
  - spec/files/test.rb
95
99
  - spec/helper.rb
100
+ - spec/integration_spec.rb
96
101
  - spec/pilfer/logger_spec.rb
97
102
  - spec/pilfer/middleware_spec.rb
98
103
  - spec/pilfer/profile_spec.rb