process-instrumentation 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +88 -0
- data/Rakefile +16 -0
- data/bin/console +6 -0
- data/bin/setup +8 -0
- data/example.gif +0 -0
- data/exe/instrument +9 -0
- data/instrumentation.gemspec +34 -0
- data/lib/assets/application.js +87 -0
- data/lib/assets/chart.min.js +15 -0
- data/lib/assets/styles.css +40 -0
- data/lib/instrumentation/bounded_array.rb +26 -0
- data/lib/instrumentation/load_average.rb +33 -0
- data/lib/instrumentation/memory.rb +25 -0
- data/lib/instrumentation/rack_app.rb +22 -0
- data/lib/instrumentation/report.rb +61 -0
- data/lib/instrumentation/version.rb +3 -0
- data/lib/instrumentation/view.rb +17 -0
- data/lib/instrumentation/webserver.rb +36 -0
- data/lib/instrumentation.rb +45 -0
- data/lib/templates/index.erb +31 -0
- metadata +182 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module Instrumentation
|
2
|
+
# Reads RSS memory from the PID specified
|
3
|
+
class Memory
|
4
|
+
def initialize(pid)
|
5
|
+
@pid = pid
|
6
|
+
end
|
7
|
+
|
8
|
+
def read
|
9
|
+
case system
|
10
|
+
when :mac_os
|
11
|
+
rss_via_ps
|
12
|
+
else
|
13
|
+
raise "Unknown system #{system.inspect}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def system
|
18
|
+
:mac_os
|
19
|
+
end
|
20
|
+
|
21
|
+
def rss_via_ps
|
22
|
+
`ps -o rss= -p #{@pid}`.strip.to_i
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'tubesock'
|
2
|
+
|
3
|
+
module Instrumentation
|
4
|
+
# Main Rack application that serves the `websocket` data or the index page
|
5
|
+
class RackApp
|
6
|
+
def initialize(report)
|
7
|
+
@report = report
|
8
|
+
@view = Instrumentation::View.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
if env['HTTP_UPGRADE'] == 'websocket'
|
13
|
+
socket = Tubesock.hijack(env)
|
14
|
+
socket.listen
|
15
|
+
@report.socket = socket
|
16
|
+
[-1, {}, []]
|
17
|
+
else
|
18
|
+
['200', { 'Content-Type' => 'text/html' }, [@view.render]]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Instrumentation
|
2
|
+
# Reads data from system and process information and writes it to
|
3
|
+
# websocket
|
4
|
+
class Report
|
5
|
+
attr_reader :memory, :loadavg
|
6
|
+
attr_accessor :socket
|
7
|
+
|
8
|
+
def initialize(pid)
|
9
|
+
@pid = pid
|
10
|
+
@sleep = 1
|
11
|
+
@memory = BoundedArray.new(300)
|
12
|
+
@loadavg = BoundedArray.new(300)
|
13
|
+
@socket = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
@thread = Thread.new do
|
18
|
+
loop do
|
19
|
+
read_data
|
20
|
+
send_data if socket
|
21
|
+
sleep @sleep
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def read_data
|
27
|
+
now = Time.now.strftime('%FT%T')
|
28
|
+
@memory = @memory << [now, read_memory]
|
29
|
+
@loadavg = @loadavg << [now, read_loadavg]
|
30
|
+
rescue => error
|
31
|
+
puts "Error when reading data: #{error.inspect}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def send_data
|
35
|
+
socket.send_data(event(:memory, @memory.items))
|
36
|
+
socket.send_data(event(:loadavg, @loadavg.items))
|
37
|
+
rescue => error
|
38
|
+
puts "Error when sending data: #{error.inspect}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def event(name, data)
|
42
|
+
{ data_type: name, data: data }.to_json
|
43
|
+
end
|
44
|
+
|
45
|
+
def read_memory
|
46
|
+
Memory.new(@pid).read
|
47
|
+
end
|
48
|
+
|
49
|
+
def read_loadavg
|
50
|
+
LoadAverage.new.read[:one]
|
51
|
+
end
|
52
|
+
|
53
|
+
def join
|
54
|
+
@thread.join
|
55
|
+
end
|
56
|
+
|
57
|
+
def shutdown
|
58
|
+
@thread.kill
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Instrumentation
|
2
|
+
# Handles rendering of ERB templates and asset loading
|
3
|
+
class View
|
4
|
+
include Erb::View
|
5
|
+
template :index
|
6
|
+
|
7
|
+
def asset(path)
|
8
|
+
File.read(asset_root.join('lib/assets', path))
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def asset_root
|
14
|
+
Instrumentation.root
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Instrumentation
|
2
|
+
# Webserver using `puma` that handles requests for stats
|
3
|
+
class Webserver
|
4
|
+
def initialize
|
5
|
+
@worker = nil
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(app, opts = {})
|
9
|
+
config = build_config(opts.merge(app: app))
|
10
|
+
|
11
|
+
@launcher = Puma::Launcher.new(config, events: Puma::Events.stdio)
|
12
|
+
@worker = Thread.new { @launcher.run }
|
13
|
+
end
|
14
|
+
|
15
|
+
def join
|
16
|
+
@worker.join
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
@launcher.stop
|
21
|
+
@worker.kill
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def build_config(opts)
|
27
|
+
Puma::Configuration.new do |c|
|
28
|
+
host = opts.fetch(:host, Puma::Configuration::DefaultTCPHost)
|
29
|
+
port = opts.fetch(:port, Puma::Configuration::DefaultTCPPort)
|
30
|
+
|
31
|
+
c.port port, host
|
32
|
+
c.app opts.fetch(:app)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'instrumentation/version'
|
2
|
+
require 'pathname'
|
3
|
+
require 'json'
|
4
|
+
require 'rack'
|
5
|
+
require 'puma'
|
6
|
+
require 'erb/view'
|
7
|
+
|
8
|
+
Erb.root = Pathname.new(__FILE__).join('..', '..').join('lib/templates')
|
9
|
+
|
10
|
+
# Instrumentation
|
11
|
+
#
|
12
|
+
# Start a server by calling:
|
13
|
+
# Instrumentation.start_server(Process.pid)
|
14
|
+
#
|
15
|
+
# By default the server is started on http://localhost:8080
|
16
|
+
module Instrumentation
|
17
|
+
def start_server(pid:, port: 8080)
|
18
|
+
report = Report.new(pid)
|
19
|
+
app = RackApp.new(report)
|
20
|
+
server = Webserver.new
|
21
|
+
|
22
|
+
report.start
|
23
|
+
server.run(app, port: port)
|
24
|
+
|
25
|
+
[server, report].map(&:join)
|
26
|
+
rescue Interrupt => _
|
27
|
+
print "\n=> Shutting down instrumentation.\n"
|
28
|
+
report.shutdown
|
29
|
+
server.stop
|
30
|
+
end
|
31
|
+
|
32
|
+
def root
|
33
|
+
Pathname.new(__FILE__).join('..', '..')
|
34
|
+
end
|
35
|
+
|
36
|
+
module_function :start_server, :root
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'instrumentation/bounded_array'
|
40
|
+
require 'instrumentation/memory'
|
41
|
+
require 'instrumentation/load_average'
|
42
|
+
require 'instrumentation/rack_app'
|
43
|
+
require 'instrumentation/report'
|
44
|
+
require 'instrumentation/view'
|
45
|
+
require 'instrumentation/webserver'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<head>
|
3
|
+
<meta charset="utf-8">
|
4
|
+
<style type="text/css"><%= asset('styles.css') %></style>
|
5
|
+
</head>
|
6
|
+
<body>
|
7
|
+
<div class="content">
|
8
|
+
<div class="container">
|
9
|
+
<div class="stats-column">
|
10
|
+
<h5>Memory Usage (RSS)</h5>
|
11
|
+
<h1 id="last-memory">-</h1>
|
12
|
+
</div>
|
13
|
+
<div class="chart-container">
|
14
|
+
<canvas id="memory" width="1000" height="300"></canvas>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="container">
|
19
|
+
<div class="stats-column">
|
20
|
+
<h5>One Minute Load Avg</h5>
|
21
|
+
<h1 id="last-loadavg">-</h1>
|
22
|
+
</div>
|
23
|
+
<div class="chart-container">
|
24
|
+
<canvas id="loadavg" width="1000" height="300"></canvas>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<script charset="utf-8"><%= asset('chart.min.js') %></script>
|
30
|
+
<script charset="utf-8"><%= asset('application.js') %></script>
|
31
|
+
</body>
|
metadata
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: process-instrumentation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Felipe Philipp
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '11.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '11.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-rg
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rack
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.0.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: tubesock
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.2.7
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.2.7
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: puma
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.6.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 3.6.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: erb-view
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.1'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.1'
|
125
|
+
description: Monitor process memory and CPU over time
|
126
|
+
email:
|
127
|
+
- felipeelias@gmail.com
|
128
|
+
executables:
|
129
|
+
- instrument
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- ".gitignore"
|
134
|
+
- ".travis.yml"
|
135
|
+
- CODE_OF_CONDUCT.md
|
136
|
+
- Gemfile
|
137
|
+
- LICENSE.txt
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- bin/console
|
141
|
+
- bin/setup
|
142
|
+
- example.gif
|
143
|
+
- exe/instrument
|
144
|
+
- instrumentation.gemspec
|
145
|
+
- lib/assets/application.js
|
146
|
+
- lib/assets/chart.min.js
|
147
|
+
- lib/assets/styles.css
|
148
|
+
- lib/instrumentation.rb
|
149
|
+
- lib/instrumentation/bounded_array.rb
|
150
|
+
- lib/instrumentation/load_average.rb
|
151
|
+
- lib/instrumentation/memory.rb
|
152
|
+
- lib/instrumentation/rack_app.rb
|
153
|
+
- lib/instrumentation/report.rb
|
154
|
+
- lib/instrumentation/version.rb
|
155
|
+
- lib/instrumentation/view.rb
|
156
|
+
- lib/instrumentation/webserver.rb
|
157
|
+
- lib/templates/index.erb
|
158
|
+
homepage: https://github.com/felipeelias/instrumentation
|
159
|
+
licenses:
|
160
|
+
- MIT
|
161
|
+
metadata: {}
|
162
|
+
post_install_message:
|
163
|
+
rdoc_options: []
|
164
|
+
require_paths:
|
165
|
+
- lib
|
166
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
requirements: []
|
177
|
+
rubyforge_project:
|
178
|
+
rubygems_version: 2.5.1
|
179
|
+
signing_key:
|
180
|
+
specification_version: 4
|
181
|
+
summary: Monitor process stats over time
|
182
|
+
test_files: []
|