space_observatory 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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