pilfer 0.0.1.pre4 → 1.0.0

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 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