singed 0.1.0 → 0.2.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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5276eb42b69baf43de15c7ad5a3549f048d00865f225998eb4479b6e7723f2b8
4
- data.tar.gz: 0f46bfb076f12a4766e060a017f2cb0e9ad6af98a96b8f96ebf05b58205aac21
3
+ metadata.gz: b94bd39d1904f3d339e34974c5ad88bec590c2373ffedc6ffba15a4bce0fbb06
4
+ data.tar.gz: dcf1af83d2b05c7cc2d20566045a99781385408c6316ef183fa3cba77ec8538f
5
5
  SHA512:
6
- metadata.gz: 81b34cf130fbe187680d65ba593ee68ce606e72cbb5db99284aba82beb6bf9ac17cef5104850a49ebba7bce87cc8a11b39f4b0897accb9bc6e0cb268ee35168e
7
- data.tar.gz: 23e265212f1f70ebe105c218dde2025728782ae1574ef2abcf4705b04e13eeab7bd9b6197442b950517492c5a540a2ebaa99478d7841b4170a8611ff668094a9
6
+ metadata.gz: c3155afc39b9bc923718a488ebc170f3c0b03ecdf8eb945af93a85ad489a3825dd464a10dc8289795b30b91e6ff0ce43a488f348a5e2cacd1308417626228edd
7
+ data.tar.gz: f0f054893e83aceb2f3342317f30e732e75c79af1fa61164e7b637fea5ae18b03b8aee5eac68b4d05facc4a37e62a5e1ef833d1aa86df55046de7e8686fc2aac
data/README.md CHANGED
@@ -1,10 +1,20 @@
1
1
  # Singed
2
2
 
3
- Singed makes it easy to get a flamegraph anywhere in your code base:
3
+ Singed makes it easy to get a flamegraph anywhere in your code base. It wraps profiling your code with [stackprof](https://github.com/tmm1/stackprof) or [rbspy](https://github.com/rbspy/rbspy), and then launching [speedscope](https://github.com/jlfwong/speedscope) to view it.
4
+
5
+ ## Installation
6
+
7
+ Add to `Gemfile`:
8
+
9
+ ```ruby
10
+ gem "singed"
11
+ ```
12
+
13
+ Then run `bundle install`
4
14
 
5
15
  ## Usage
6
16
 
7
- To profile your code, and launch [speedscope](https://github.com/jlfwong/speedscope) for viewing it:
17
+ Simplest is calling with a block:
8
18
 
9
19
  ```ruby
10
20
  flamegraph {
@@ -22,7 +32,7 @@ Singed.output_directory = "tmp/slowness-exploration"
22
32
  If you are calling it in a loop, or with different variations, you can include a label on the filename:
23
33
 
24
34
  ```ruby
25
- flamegraph(label: "rspec") {
35
+ flamegraph("rspec") {
26
36
  # your code here
27
37
  }
28
38
  ```
@@ -64,7 +74,7 @@ class EmployeesController < ApplicationController
64
74
  end
65
75
  ```
66
76
 
67
- This won't catch the entire request though, just once it's been routed to controller and a response has been served.
77
+ This won't catch the entire request though, just once it's been routed to controller and a response has been served (ie no middleware).
68
78
 
69
79
  ### Rack/Rails requests
70
80
 
@@ -84,7 +94,7 @@ There is a `singed` command line you can use that will record a flamegraph from
84
94
 
85
95
  ```shell
86
96
  $ bundle binstub singed # if you want to be able to call it like bin/singed
87
- $ bundle exec singed -- bin/rails
97
+ $ bundle exec singed -- bin/rails runner 'Model.all.to_a'
88
98
  ```
89
99
 
90
100
  The flamegraph is opened afterwards.
@@ -98,5 +108,5 @@ The `open` is expected to be available.
98
108
 
99
109
  ## Alternatives
100
110
 
101
- - using [rbspy](https://rbspy.github.io/) directory
111
+ - using [rbspy](https://rbspy.github.io/) directly
102
112
  - using [stackprof](https://github.com/tmm1/stackprof) (a dependency of singed) directly
data/lib/singed/cli.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'shellwords'
2
2
  require 'tmpdir'
3
3
  require 'optionparser'
4
+ require 'pathname'
4
5
 
5
6
  # NOTE: we defer requiring singed until we run. that lets Rails load it if its in the gemfile, so the railtie has had a chance to run
6
7
 
@@ -64,6 +65,7 @@ module Singed
64
65
 
65
66
  Singed.output_directory = @output_directory if @output_directory
66
67
  Singed.output_directory ||= Dir.tmpdir
68
+ FileUtils.mkdir_p Singed.output_directory
67
69
  @filename = Singed::Flamegraph.generate_filename(label: 'cli')
68
70
 
69
71
  options = {
@@ -86,11 +88,19 @@ module Singed
86
88
  prompt_password
87
89
  end
88
90
 
89
- Bundler.with_unbundled_env do
91
+ rbspy = lambda do
90
92
  # don't run things with spring, because it forks and rbspy won't see it
91
93
  sudo ['rbspy', *rbspy_args], reason: 'Singed needs to run as root, but will drop permissions back to your user.', env: { 'DISABLE_SPRING' => '1' }
92
94
  end
93
95
 
96
+ if defined?(Bundler)
97
+ Bundler.with_unbundled_env do
98
+ rbspy.call
99
+ end
100
+ else
101
+ rbspy.call
102
+ end
103
+
94
104
  unless filename.exist?
95
105
  puts "#{filename} doesn't exist. Maybe rbspy had a failure capturing it? Check the scrollback."
96
106
  exit 1
@@ -102,9 +112,9 @@ module Singed
102
112
  end
103
113
 
104
114
  # clean the report, similar to how Singed::Report does
105
- json = JSON.parse(filename.read).with_indifferent_access
115
+ json = JSON.parse(filename.read)
106
116
  json['shared']['frames'].each do |frame|
107
- frame[:file] = Singed.filter_line(frame[:file])
117
+ frame['file'] = Singed.filter_line(frame['file'])
108
118
  end
109
119
  filename.write(JSON.dump(json))
110
120
 
@@ -53,7 +53,7 @@ module Singed
53
53
  end
54
54
 
55
55
  def self.generate_filename(label: nil, time: Time.now) # rubocop:disable Rails/TimeZone
56
- formatted_time = time.to_formatted_s(:number)
56
+ formatted_time = time.strftime('%Y%m%d%H%M%S')
57
57
  basename_parts = ['speedscope', label, formatted_time].compact
58
58
 
59
59
  file = Singed.output_directory.join("#{basename_parts.join('-')}.json")
@@ -1,15 +1,15 @@
1
1
  module Kernel
2
- def flamegraph(label = nil, open: true, ignore_gc: false, interval: 1000, &block)
2
+ def flamegraph(label = nil, open: true, ignore_gc: false, interval: 1000, io: $stdout, &block)
3
3
  fg = Singed::Flamegraph.new(label: label, ignore_gc: ignore_gc, interval: interval)
4
4
  result = fg.record(&block)
5
5
  fg.save
6
6
 
7
7
  if open
8
8
  # use npx, so we don't have to add it as a dependency
9
- puts "🔥📈 #{'Captured flamegraph, opening with'.colorize(:bold).colorize(:red)}: #{fg.open_command}"
9
+ io.puts "🔥📈 #{'Captured flamegraph, opening with'.colorize(:bold).colorize(:red)}: #{fg.open_command}"
10
10
  fg.open
11
11
  else
12
- puts "🔥📈 #{'Captured flamegraph to file'.colorize(:bold).colorize(:red)}: #{fg.filename}"
12
+ io.puts "🔥📈 #{'Captured flamegraph to file'.colorize(:bold).colorize(:red)}: #{fg.filename}"
13
13
  end
14
14
 
15
15
  result
data/lib/singed.rb CHANGED
@@ -13,7 +13,7 @@ module Singed
13
13
  end
14
14
 
15
15
  def self.output_directory
16
- @output_directory || raise("output directory hasn't been set!")
16
+ @output_directory
17
17
  end
18
18
 
19
19
  def enabled=(enabled)
data/singed.gemspec CHANGED
@@ -3,7 +3,7 @@
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'singed'
5
5
 
6
- spec.version = '0.1.0'
6
+ spec.version = '0.2.0'
7
7
  spec.authors = ['Josh Nichols']
8
8
  spec.email = ['josh.nichols@gusto.com']
9
9
 
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency 'stackprof'
23
23
 
24
24
  spec.add_development_dependency 'rake', '~> 13.0'
25
+ spec.add_development_dependency 'rspec'
25
26
 
26
27
  # For more information and examples about making a new gem, checkout our
27
28
  # guide at: https://bundler.io/guides/creating_gem.html
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: singed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Nichols
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-01-20 00:00:00.000000000 Z
11
+ date: 2023-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description:
56
70
  email:
57
71
  - josh.nichols@gusto.com