space_observatory 0.0.1 → 0.0.2

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
  SHA1:
3
- metadata.gz: c33aabad489c6d4e3fe00a0d270daaf7694450aa
4
- data.tar.gz: 2c22ce59b2d4d6c2aba4310d931261eae95f4d03
3
+ metadata.gz: cbfdd79f8b24c39b374ca7bd7f23540ea545e602
4
+ data.tar.gz: 05c51b5ed6e113c65617c1bb74d0120ddcdcc542
5
5
  SHA512:
6
- metadata.gz: 5056147bf38a148f8a28c6a35af85f6a691b4073507291224ec8d45630cf1a9556da97e5788453fb2164369554e2a9bcfd8151016b018e76580af2909d3974e6
7
- data.tar.gz: df671b5081f41a0418ccf499860cb7c16b7732a36de3b6a013ab5f04df857e3a61907515eccc4e47a9202f14eb76e4fca33e85c1faa335c6ad7d319c7ec3fa40
6
+ metadata.gz: d48ce0353e37319ee548bda34aa224e75edbeb69c18b41838676cff0635c8c88f5db33f7a3eee2c00dd4e11f4b6dca280f9f735dd88dc0d15fece64ec5ac213f
7
+ data.tar.gz: cdb858c3109a0405c8e498419f13c9dbbe8901598f5f13efd6fb51fb96fd12a1191ddc9381a81b6f1bb984f280e28f07e166eca208cfeb95044a8b4440640ae5
data/Gemfile CHANGED
@@ -23,5 +23,6 @@
23
23
 
24
24
  source 'https://rubygems.org'
25
25
 
26
+ gem 'rack', git: 'git@github.com:rack/rack.git'
26
27
  # Specify your gem's dependencies in space_observatory.gemspec
27
28
  gemspec
data/README.md CHANGED
@@ -7,13 +7,38 @@ This is an easy add-on for you to observe your ObjectSpace.
7
7
  - Pure ruby. NO C extensions.
8
8
  - Drop-in design that requires NO modifications to your program.
9
9
  - Minimal overhead. Does all jobs except data collection in a separate process.
10
+ - Native support Rails, Sinatra, and non-Web daemons.
10
11
 
11
12
  ## Installation
12
13
 
13
14
  As usual.
14
15
 
16
+ **NOTE** however that as of this writing, WEBrick do not support websockets (necessary for this lib). You need a websockets-aware rack handler like Puma, Passanger, whatever.
17
+
15
18
  ## Usage
16
19
 
20
+ ### on Rails
21
+
22
+ ```ruby
23
+ gem 'space_observatory', require: 'space_observatory/railtie'
24
+ ```
25
+
26
+ And you are done.
27
+
28
+ ### Pure Rack / Sinatra / Padrino etc
29
+
30
+ ```ruby
31
+ gem 'space_observatory', require: 'space_observatory/rack_middleware'
32
+ ```
33
+
34
+ Also in your `config.ru` file add:
35
+
36
+ ```ruby
37
+ use SpaceObservatory::RackMiddleware
38
+ ```
39
+
40
+ ### Versatile use case including non-Web daemons
41
+
17
42
  ```bash
18
43
  bundle exec with-space-observatory.rb --port=1234 -- ruby bin/rails server --port=5678
19
44
  ```
@@ -24,5 +24,5 @@
24
24
  require_relative "space_observatory/version"
25
25
 
26
26
  module SpaceObservatory
27
- # Your code goes here...
27
+ require_relative 'space_observatory/railtie' if defined? ::Rails
28
28
  end
@@ -22,13 +22,13 @@
22
22
  # SOFTWARE.
23
23
 
24
24
  require 'rubygems'
25
- require 'open3'
26
- require 'sync'
25
+ require 'bundler/setup'
27
26
  require 'rack'
28
27
  require 'slop'
29
28
  require_relative '../space_observatory'
29
+ require_relative 'rack_middleware'
30
30
 
31
- class SpaceObservatory::BaseStation
31
+ class SpaceObservatory::BaseStation < SpaceObservatory::RackMiddleware
32
32
  # Fork a base station process
33
33
  # @param [Array] argv The ::ARGV
34
34
  # @return [IO, IO, Integer, Array] child's socket, pid, and argv.
@@ -44,7 +44,6 @@ class SpaceObservatory::BaseStation
44
44
  def self.construct
45
45
  obj = new ARGV, STDIN, STDOUT
46
46
  if obj.need_rackup?
47
- obj.start_collector
48
47
  obj.rackup
49
48
  else
50
49
  obj.banner
@@ -74,17 +73,18 @@ class SpaceObservatory::BaseStation
74
73
  @stdout.sync = true # we need line IO
75
74
  @opts, @argw = self.class.parse argv
76
75
  @argw.shift if @argw.first == '--'
77
- @started = Time.at 0
78
- @finished = Time.at 0
79
- @jsons = Array.new
80
- @rwlock = Sync.new
81
- @expires = @opts['ttl'] || 60 # 300 # 3600
76
+
77
+ super nil, '/', @opts['ttl'] || 60 # 300 # 3600
82
78
  end
83
79
 
84
80
  def rackup
85
81
  Rack::Handler::WEBrick.run self, Port: @opts['port']
86
82
  end
87
83
 
84
+ def need_rackup?
85
+ not @opts['h'] and not @argw.empty?
86
+ end
87
+
88
88
  def banner
89
89
  @stdout.puts "space_observatory norun"
90
90
  @stdout.puts @opts.help if @opts['h']
@@ -92,13 +92,28 @@ class SpaceObservatory::BaseStation
92
92
  @stdout.close_write
93
93
  end
94
94
 
95
+ private
96
+
95
97
  def start_collector
98
+ retun unless need_rackup?
99
+
100
+ Thread.start do
101
+ loop do
102
+ env = @queue.deq # block here
103
+ @mutex.synchronize do
104
+ next if Time.now - @started < @expires
105
+ @stdout.puts "space_observatory probe"
106
+ end
107
+ end
108
+ end
109
+
96
110
  Thread.start do
97
111
  # needs handshale
98
112
  @stdout.puts "space_observatory ok"
99
113
  @stdin.gets # wait execve(2)
100
114
  @stdout.puts "space_observatory setup"
101
- @stdout.puts "space_observatory probe"
115
+
116
+ tmp = Tempfile.new ''
102
117
  while line = @stdin.gets
103
118
  case line
104
119
  when "space_observatory projectile_eof\n"
@@ -107,57 +122,20 @@ class SpaceObservatory::BaseStation
107
122
  return
108
123
  when "space_observatory begin_objspace\n"
109
124
  @started = Time.now
110
- @rwlock.lock Sync::EX
111
- @jsons = Array.new
125
+ @mutex.lock
126
+ tmp.truncate 0
112
127
  when "space_observatory end_objspace\n"
113
- @rwlock.unlock Sync::EX
128
+ cook tmp
129
+ @mutex.unlock
114
130
  @finished = Time.now
115
131
  STDERR.printf "took %fsec\n", (@finished - @started).to_f
116
132
  when /\A{/o
117
133
  # This is the output of ObjectSpace.dump_all
118
- @jsons.push line
134
+ tmp.write line
119
135
  else
120
136
  raise "TBW: #{line}"
121
137
  end
122
138
  end
123
139
  end
124
140
  end
125
-
126
- def need_rackup?
127
- not @opts['h'] and not @argw.empty?
128
- end
129
-
130
- def call env
131
- # TODO: more "proper" JSON
132
- enum = Enumerator.new do |y|
133
- @rwlock.synchronize Sync::EX do
134
- if Time.now - @started >= @expires
135
- @stdout.puts "space_observatory probe"
136
- IO.select [@stdin], [], [], 10
137
- @started = Time.now # prevent further probe
138
- end
139
- end
140
- Thread.pass
141
- @rwlock.synchronize Sync::SH do
142
- id = @finished.to_i
143
- y.yield <<-"]"
144
- {
145
- "jsonrpc" : "2.0",
146
- "id" : #{id},
147
- "result" : [
148
- ]
149
- @jsons.each_with_index do |i, j|
150
- y.yield "," unless j.zero?
151
- y.yield i
152
- end
153
- y.yield "]\n}\n"
154
- end
155
- end
156
-
157
- return [
158
- 200,
159
- { 'Content-Type' => 'application/json' },
160
- enum
161
- ]
162
- end
163
141
  end
@@ -0,0 +1,119 @@
1
+ #! /your/favourite/path/to/ruby
2
+ # -*- coding: utf-8; mode: ruby; ruby-indent-level: 2 -*-
3
+ #
4
+ # Copyright (c) 2014 Urabe, Shyouhei
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'objspace'
25
+ require 'thread'
26
+ require 'tempfile'
27
+ require 'open3'
28
+ require 'rubygems'
29
+ require 'bundler/setup'
30
+ require_relative '../space_observatory'
31
+
32
+ class SpaceObservatory::RackMiddleware
33
+
34
+ def initialize app, path = '/space', expires = 60 # 300 # 3600
35
+ @app = app
36
+ @path = path
37
+ @expires = expires
38
+ @mutex = Mutex.new
39
+ @queue = Queue.new
40
+ @latest = nil
41
+ @started = Time.at 0
42
+ @finished = Time.at 0
43
+ @thread = start_collector
44
+ end
45
+
46
+ def call env
47
+ return @app.call env if @app and env['PATH_INFO'] != @path
48
+
49
+ @queue.enq env
50
+ hdr = {
51
+ 'Connection' => 'close',
52
+ 'Content-Type' => 'application/json',
53
+ 'rack.hijack' => lambda do |fp|
54
+ Thread.start do
55
+ begin
56
+ Thread.pass until @latest
57
+ @mutex.synchronize do
58
+ @latest.rewind
59
+ IO.copy_stream @latest, fp
60
+ end
61
+ rescue Errno::ENOTCONN
62
+ ensure
63
+ fp.close
64
+ end
65
+ end
66
+ end
67
+ }
68
+ return [ 200, hdr, nil ]
69
+ end
70
+
71
+ private
72
+
73
+ def start_collector
74
+ Thread.start do
75
+ loop do
76
+ env = @queue.deq # block here
77
+ @mutex.synchronize do
78
+ next if Time.now - @started < @expires
79
+
80
+ @started = Time.now # prevent further probe
81
+ env['rack.errors'] << "Collection happen at #@started\n"
82
+ tmp1 = ObjectSpace.dump_all output: :file
83
+ cook tmp1
84
+ tmp1.close
85
+ @finished = Time.now
86
+ env['rack.errors'] << "Collection done in #{@finished - @started} secs.\n"
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ def cook io
93
+ @latest ||= Tempfile.new ''
94
+ @latest.rewind
95
+ @latest.truncate 0
96
+ @latest.print <<-"end".gsub(/^\s+(\S)/, '\\1').gsub(/[\r\n]/, "\r\n")
97
+ HTTP/1.1 200 OK
98
+ Content-Type: application/json
99
+ Connection: close
100
+
101
+ end
102
+ @latest.puts <<-"]".gsub(/^\s+/, '')
103
+ {
104
+ "jsonrpc" : "2.0",
105
+ "id" : #{@started.to_i},
106
+ "result" : [
107
+ ]
108
+ # This subprocessing is CHAPER than gsub-ing ourselves because
109
+ # gsub creates TONS of garbage string objects, which would be
110
+ # counted in the next ObjectSpace.dump_all call.
111
+ #
112
+ # Also note that this can totally be avoided if
113
+ # ObjectSpace.dump_all have generated valid JSON from the outset.
114
+ Open3.pipeline_r "cat #{io.path}", 'sed s/$/,/' do |r,|
115
+ IO.copy_stream r, @latest
116
+ end
117
+ @latest.print "]\n}\n"
118
+ end
119
+ end
@@ -0,0 +1,31 @@
1
+ #! /your/favourite/path/to/ruby
2
+ # -*- coding: utf-8; mode: ruby; ruby-indent-level: 2 -*-
3
+ #
4
+ # Copyright (c) 2014 Urabe, Shyouhei
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ # SOFTWARE.
23
+
24
+ require 'rubygems'
25
+ require_relative 'rack_middleware'
26
+
27
+ class SpaceObservatory::Railtie < ::Rails::Railtie
28
+ initializer "space_observatory.install_middleware" do |app|
29
+ app.config.middleware.insert_before "ActionDispatch::Static", "SpaceObservatory::RackMiddleware"
30
+ end
31
+ end
@@ -21,5 +21,5 @@
21
21
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
22
  # SOFTWARE.
23
23
  module SpaceObservatory
24
- VERSION = "0.0.1"
24
+ VERSION = "0.0.2"
25
25
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: space_observatory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Urabe, Shyouhei
8
8
  autorequire:
9
9
  bindir: exec
10
10
  cert_chain: []
11
- date: 2014-07-22 00:00:00.000000000 Z
11
+ date: 2014-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -168,6 +168,8 @@ files:
168
168
  - exec/with-space-observatory.rb
169
169
  - lib/space_observatory.rb
170
170
  - lib/space_observatory/base_station.rb
171
+ - lib/space_observatory/rack_middleware.rb
172
+ - lib/space_observatory/railtie.rb
171
173
  - lib/space_observatory/version.rb
172
174
  - space_observatory.gemspec
173
175
  homepage: https://github.com/shyouhei/space_observatory