onis 0.1

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.
Files changed (6) hide show
  1. data/README.md +81 -0
  2. data/bin/onis +70 -0
  3. data/lib/onis.rb +3 -0
  4. data/lib/onis/base.rb +35 -0
  5. data/onis.gemspec +29 -0
  6. metadata +59 -0
@@ -0,0 +1,81 @@
1
+ # onis
2
+ (pronounced onis)
3
+
4
+ Onis gives you introspection into object counts of live running ruby process.
5
+
6
+ ## Install
7
+
8
+ $ sudo gem install onis
9
+
10
+ ## Example
11
+
12
+ $ cd onis/
13
+
14
+ $ cat test/stringpwd.rb &
15
+ require 'onis'
16
+ puts Process.pid
17
+ a = []
18
+ while true ; a << "foo" ; sleep(0.5) ; end
19
+
20
+ $ onis
21
+ PID COMMAND
22
+ ------------------------------------------------------------
23
+ 26584 ruby -I lib/ test/stringpwnd.rb
24
+
25
+ $ onis -f 26584
26
+ Class Count
27
+ --------------------------------------------------------
28
+ String 3483
29
+ Class 156
30
+ Array 55
31
+ Module 25
32
+ Regexp 9
33
+ File 8
34
+ Hash 7
35
+ Float 6
36
+ Object 3
37
+ ...
38
+
39
+ ## Color!
40
+
41
+ $ onis -f -c 26584
42
+
43
+ ## How it works
44
+
45
+ 1. Onis drops a tempfile named after the pid `onis.<pid>`
46
+ 2. Onis then traps SIGUSR1
47
+ 3. When SIGUSR1 is sent to a process that
48
+ has `require`d Onis, Onis will dump the ObjectSpace and counts
49
+ to that tempfile.
50
+
51
+ ## TODO:
52
+ * handle `fork`
53
+
54
+ ## Thanks
55
+ - Aman Gupta (tmm1) for inspiration and example
56
+ - Ryan Tomayko for playing that great music at Columbus Cafe
57
+ and telling me to take this one step further
58
+
59
+ ## License
60
+ Copyright (c) 2009 Blake Mizerany
61
+
62
+ Permission is hereby granted, free of charge, to any person
63
+ obtaining a copy of this software and associated documentation
64
+ files (the "Software"), to deal in the Software without
65
+ restriction, including without limitation the rights to use,
66
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
67
+ copies of the Software, and to permit persons to whom the
68
+ Software is furnished to do so, subject to the following
69
+ conditions:
70
+
71
+ The above copyright notice and this permission notice shall be
72
+ included in all copies or substantial portions of the Software.
73
+
74
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
75
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
76
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
77
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
78
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
79
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
80
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
81
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
3
+
4
+ require 'optparse'
5
+ require 'onis/base'
6
+
7
+ # default options
8
+ pid = nil
9
+ force = false
10
+ watch = false
11
+ color = false
12
+
13
+ # setup command
14
+ command = `uname`.chomp == "Darwin" ? "command" : "cmd"
15
+ psax = `ps -axo pid,#{command}`
16
+ format = "%-10s %s\n"
17
+
18
+ ARGV.options do |o|
19
+ o.banner = "Usage: onis [options] [pid]"
20
+ o.separator ""
21
+ o.separator "Run without params for process list"
22
+
23
+ o.on("-f", "--force", "force report") { force = true }
24
+ o.on("-w", "--watch", "watch report. -f is implied") { watch = true }
25
+ o.on("-c", "--color", "highlight every other line in report") { color = true }
26
+
27
+ o.on_tail("-h", "--help", "show this message") { abort(o.to_s) }
28
+ o.parse!
29
+ end
30
+
31
+ P = lambda {|line|
32
+ @n ||= 0
33
+ print "\e[7m" if color && ((@n += 1) % 2).zero?
34
+ puts line
35
+ print "\e[m" if color
36
+ }
37
+
38
+ if pid = ARGV.shift
39
+ if watch
40
+ exec "watch -n0 \"#{$0} -f #{pid}\""
41
+ elsif force
42
+ Process.kill("SIGUSR1", pid.to_i)
43
+ sleep(0.5)
44
+ end
45
+
46
+ pfp = Onis::Base.path_for_pid(pid)
47
+ abort("report for #{pid} not found") if !File.file?(pfp)
48
+
49
+ open(pfp) do |f|
50
+ format = "%-45s %-10s\n"
51
+ puts format % %w|Class Count|
52
+ puts "-" * 56
53
+ f.each_line do |line|
54
+ P[format % line.chomp.split(",")]
55
+ end
56
+ end
57
+ else
58
+ print format % %w|PID COMMAND|
59
+ puts "-" * 60
60
+ psax.each_line do |line|
61
+ next unless line =~ /^\d+/
62
+ pid = line.slice!(/^\d+ /).strip
63
+ next if pid == Process.pid.to_s
64
+ pfp = Onis::Base.path_for_pid(pid)
65
+ next if !File.file?(pfp)
66
+ P[format % [pid, line]]
67
+ end
68
+ end
69
+
70
+ #vim: syn=ruby
@@ -0,0 +1,3 @@
1
+ require 'onis/base'
2
+
3
+ Onis::Base.start!
@@ -0,0 +1,35 @@
1
+ require 'tempfile'
2
+ require 'fileutils'
3
+
4
+ module Onis
5
+ module Base
6
+ def self.drop_pid(pid = Process.pid)
7
+ path_for_pid(pid).tap {|pfp| FileUtils.touch(pfp)}
8
+ end
9
+
10
+ def self.path_for_pid(pid)
11
+ File.join(Dir.tmpdir, "onis.#{pid}")
12
+ end
13
+
14
+ def self.start!
15
+ pfp = drop_pid
16
+ trap("USR1") do
17
+ open(pfp, 'w') do |f|
18
+ ObjectInspector.all.each do |o|
19
+ f.puts o.join(",")
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ module ObjectInspector
27
+ def self.all
28
+ h = Hash.new(0)
29
+ ObjectSpace.each_object do |o|
30
+ h[o.class] += 1
31
+ end
32
+ h.sort {|a, b| b.last <=> a.last}
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+
5
+ s.name = 'onis'
6
+ s.version = '0.1'
7
+ s.date = '2009-10-27'
8
+
9
+ s.description = "Live ObjectSpace introspection"
10
+ s.summary = s.description
11
+
12
+ s.authors = ["Blake Mizerany"]
13
+ s.email = "blake.mizerany@gmail.com"
14
+
15
+ s.files = %w[
16
+ README.md
17
+ onis.gemspec
18
+ lib/onis.rb
19
+ lib/onis/base.rb
20
+ bin/onis
21
+ ]
22
+ s.executables = ['onis']
23
+
24
+ s.extra_rdoc_files = %w[README.md]
25
+
26
+ s.homepage = "http://github.com/bmizerany/onis/"
27
+ s.require_paths = %w[lib]
28
+ s.rubygems_version = '1.1.1'
29
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: onis
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Blake Mizerany
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-27 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Live ObjectSpace introspection
17
+ email: blake.mizerany@gmail.com
18
+ executables:
19
+ - onis
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.md
24
+ files:
25
+ - README.md
26
+ - onis.gemspec
27
+ - lib/onis.rb
28
+ - lib/onis/base.rb
29
+ - bin/onis
30
+ has_rdoc: true
31
+ homepage: http://github.com/bmizerany/onis/
32
+ licenses: []
33
+
34
+ post_install_message:
35
+ rdoc_options: []
36
+
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ requirements: []
52
+
53
+ rubyforge_project:
54
+ rubygems_version: 1.3.4
55
+ signing_key:
56
+ specification_version: 2
57
+ summary: Live ObjectSpace introspection
58
+ test_files: []
59
+