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 +4 -4
- data/Gemfile +1 -0
- data/README.md +25 -0
- data/lib/space_observatory.rb +1 -1
- data/lib/space_observatory/base_station.rb +30 -52
- data/lib/space_observatory/rack_middleware.rb +119 -0
- data/lib/space_observatory/railtie.rb +31 -0
- data/lib/space_observatory/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbfdd79f8b24c39b374ca7bd7f23540ea545e602
|
4
|
+
data.tar.gz: 05c51b5ed6e113c65617c1bb74d0120ddcdcc542
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d48ce0353e37319ee548bda34aa224e75edbeb69c18b41838676cff0635c8c88f5db33f7a3eee2c00dd4e11f4b6dca280f9f735dd88dc0d15fece64ec5ac213f
|
7
|
+
data.tar.gz: cdb858c3109a0405c8e498419f13c9dbbe8901598f5f13efd6fb51fb96fd12a1191ddc9381a81b6f1bb984f280e28f07e166eca208cfeb95044a8b4440640ae5
|
data/Gemfile
CHANGED
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
|
```
|
data/lib/space_observatory.rb
CHANGED
@@ -22,13 +22,13 @@
|
|
22
22
|
# SOFTWARE.
|
23
23
|
|
24
24
|
require 'rubygems'
|
25
|
-
require '
|
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
|
-
|
78
|
-
@
|
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
|
-
|
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
|
-
@
|
111
|
-
|
125
|
+
@mutex.lock
|
126
|
+
tmp.truncate 0
|
112
127
|
when "space_observatory end_objspace\n"
|
113
|
-
|
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
|
-
|
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
|
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.
|
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-
|
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
|