puma-status 1.0 → 1.4

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
  SHA256:
3
- metadata.gz: 2f95a656741b1b1aafddb43954a144399db944b78ca6384e9ec77cc0783ca750
4
- data.tar.gz: a1b2f9addd173d84404bb94e26ec38522586d72fca0e190562d86d9a3e95b92a
3
+ metadata.gz: 22bea1d3a501185590a81878994456d75a4c5375794221bdeb51b3283d65cceb
4
+ data.tar.gz: a2670a54fdd6c4dae1040c59882f969ba1aff3487076d75962e2fa105da32b59
5
5
  SHA512:
6
- metadata.gz: a44a39a95544ba5a9cd42b4e87ac2409a5b0c3623dad6af622c7a589be755c91ab26af03daf7a7304d2ba0da8e9a216a6a850dd5409e7f75d8eee2e5a6c79a23
7
- data.tar.gz: a344489b4164ff044ff37ac39b4cfaab7a9f4ea74fe2c1cc12a6c124d3804a94260423c2be8ca12d02b42f30754a30f630de8bf93cd723a12385a6b7dad211a6
6
+ metadata.gz: '09d1cfd981ee0c5092e9bda66009e2a4b517f3bfe3987559cfb571a9a4aa0c880e6ca45061cbd0a0c8bbc5016d2a11ba3410facc67b9924ab7643512110b2711'
7
+ data.tar.gz: 023b10377d8567d59c3b75028c4cd54c2f3db12d686bcf41d5a6fcd69aabf45c6e5a89b3c956afa8e98d7ec696c5ef85801fd6a8625adf6b9d42a1aea9a584fc
data/lib/core.rb CHANGED
@@ -3,13 +3,14 @@ require 'json'
3
3
  require 'net_x/http_unix'
4
4
  require 'openssl'
5
5
  require 'time'
6
+ require 'open3'
6
7
  require_relative 'stats'
7
8
 
8
9
  def get_stats(state_file_path)
9
10
  puma_state = YAML.load_file(state_file_path)
10
11
 
11
12
  uri = URI.parse(puma_state["control_url"])
12
-
13
+
13
14
  address = if uri.scheme =~ /unix/i
14
15
  [uri.scheme, '://', uri.host, uri.path].join
15
16
  else
@@ -19,7 +20,7 @@ def get_stats(state_file_path)
19
20
  client = NetX::HTTPUnix.new(address, uri.port)
20
21
 
21
22
  if uri.scheme =~ /ssl/i
22
- client.use_ssl = true
23
+ client.use_ssl = true
23
24
  client.verify_mode = OpenSSL::SSL::VERIFY_NONE if ENV['SSL_NO_VERIFY'] == '1'
24
25
  end
25
26
 
@@ -32,10 +33,26 @@ def get_stats(state_file_path)
32
33
  hydrate_stats(stats, puma_state, state_file_path)
33
34
  end
34
35
 
36
+ def get_memory_from_top(raw_memory)
37
+ case raw_memory[-1].downcase
38
+ when 'g'
39
+ (raw_memory[0...-1].to_f*1024).to_i
40
+ when 'm'
41
+ raw_memory[0...-1].to_i
42
+ else
43
+ raw_memory.to_i/1024
44
+ end
45
+ end
46
+
47
+ PID_COLUMN = 0
48
+ MEM_COLUMN = 5
49
+ CPU_COLUMN = 8
50
+ OPEN3_STDOUT = 1
51
+
35
52
  def get_top_stats(pids)
36
53
  pids.each_slice(19).inject({}) do |res, pids19|
37
- top_result = `top -b -n 1 -p #{pids19.join(',')} | tail -n #{pids19.length}`
38
- top_result.split("\n").map { |row| r = row.split(' '); [r[0].to_i, r[5].to_i/1024, r[8].to_f] }
54
+ top_result = Open3.popen3({ 'LC_ALL' => 'C' }, "top -b -n 1 -p #{pids19.map(&:to_i).join(',')}")[OPEN3_STDOUT].read
55
+ top_result.split("\n").last(pids19.length).map { |row| r = row.split(' '); [r[PID_COLUMN].to_i, get_memory_from_top(r[MEM_COLUMN]), r[CPU_COLUMN].to_f] }
39
56
  .inject(res) { |hash, row| hash[row[0]] = { mem: row[1], pcpu: row[2] }; hash }
40
57
  res
41
58
  end
@@ -65,7 +82,7 @@ def format_stats(stats)
65
82
  if stats.booting?
66
83
  master_line += " #{warn("booting")}"
67
84
  else
68
- master_line += " | Load: #{color(75, 50, stats.load, asciiThreadLoad(stats.running_threads, stats.max_threads))}"
85
+ master_line += " | Load: #{color(75, 50, stats.load, asciiThreadLoad(stats.running_threads, stats.spawned_threads, stats.max_threads))}"
69
86
  master_line += " | Req: #{stats.requests_count}" if stats.requests_count
70
87
  end
71
88
 
@@ -77,7 +94,7 @@ def format_stats(stats)
77
94
  elsif wstats.killed?
78
95
  worker_line += " #{error("killed")}"
79
96
  else
80
- worker_line += " | Load: #{color(75, 50, wstats.load, asciiThreadLoad(wstats.running_threads, wstats.max_threads))}"
97
+ worker_line += " | Load: #{color(75, 50, wstats.load, asciiThreadLoad(wstats.running_threads, wstats.spawned_threads, wstats.max_threads))}"
81
98
  worker_line += " | Phase: #{error(wstats.phase)}" if wstats.phase != stats.phase
82
99
  worker_line += " | Req: #{wstats.requests_count}" if wstats.requests_count
83
100
  worker_line += " Queue: #{error(wstats.backlog.to_s)}" if wstats.backlog > 0
data/lib/helpers.rb CHANGED
@@ -29,11 +29,16 @@ def color(critical, warn, value, str = nil)
29
29
  colorize(str, color_level)
30
30
  end
31
31
 
32
- def asciiThreadLoad(idx, total)
32
+ def asciiThreadLoad(running, spawned, total)
33
33
  full = "█"
34
- empty= "░"
34
+ half= "░"
35
+ empty = " "
35
36
 
36
- "#{idx}[#{full*idx}#{empty*(total-idx)}]#{total}"
37
+ full_count = running
38
+ half_count = [spawned - running, 0].max
39
+ empty_count = total - half_count - full_count
40
+
41
+ "#{running}[#{full*full_count}#{half*half_count}#{empty*empty_count}]#{total}"
37
42
  end
38
43
 
39
44
  def seconds_to_human(seconds)
@@ -44,8 +49,10 @@ def seconds_to_human(seconds)
44
49
  #=> 23h59m
45
50
  #=> 1d 0h
46
51
  #=> 24d
47
-
48
- if seconds < 60*60
52
+
53
+ if seconds <= 0
54
+ "--m--s"
55
+ elsif seconds < 60*60
49
56
  "#{(seconds/60).to_s.rjust(2, ' ')}m#{(seconds%60).to_s.rjust(2, ' ')}s"
50
57
  elsif seconds >= 60*60*1 && seconds < 60*60*24
51
58
  "#{(seconds/(60*60*1)).to_s.rjust(2, ' ')}h#{((seconds%(60*60*1))/60).to_s.rjust(2, ' ')}m"
data/lib/puma-status.rb CHANGED
@@ -17,11 +17,21 @@ def run
17
17
  begin
18
18
  debug "State file: #{state_file_path}"
19
19
  format_stats(get_stats(state_file_path))
20
- rescue Errno::ENOENT
21
- errors << "#{warn(state_file_path)} doesn't exists"
20
+ rescue Errno::ENOENT => e
21
+ if e.message =~ /#{state_file_path}/
22
+ errors << "#{warn(state_file_path)} doesn't exists"
23
+ elsif e.message =~ /connect\(2\) for [^\/]/
24
+ errors << "#{warn("Relative Unix socket")}: the Unix socket of the control app has a relative path. Please, ensure you are running from the same folder has puma."
25
+ else
26
+ errors << "#{error(state_file_path)} an unhandled error occured: #{e.inspect}"
27
+ end
22
28
  nil
23
- rescue Errno::EISDIR
24
- errors << "#{warn(state_file_path)} isn't a state file"
29
+ rescue Errno::EISDIR => e
30
+ if e.message =~ /#{state_file_path}/
31
+ errors << "#{warn(state_file_path)} isn't a state file"
32
+ else
33
+ errors << "#{error(state_file_path)} an unhandled error occured: #{e.inspect}"
34
+ end
25
35
  nil
26
36
  rescue => e
27
37
  errors << "#{error(state_file_path)} an unhandled error occured: #{e.inspect}"
data/lib/stats.rb CHANGED
@@ -41,10 +41,12 @@ class Stats
41
41
  @wstats.dig('last_status', 'running') || @wstats['running'] || 0
42
42
  end
43
43
  alias :total_threads :running
44
+ alias :spawned_threads :running
44
45
 
45
46
  def max_threads
46
47
  @wstats.dig('last_status', 'max_threads') || @wstats['max_threads'] || 0
47
48
  end
49
+ alias :total_threads :max_threads
48
50
 
49
51
  def pool_capacity
50
52
  @wstats.dig('last_status', 'pool_capacity') || @wstats['pool_capacity'] || 0
@@ -123,6 +125,10 @@ class Stats
123
125
  workers.reduce(0) { |total, wstats| total + wstats.running_threads }
124
126
  end
125
127
 
128
+ def spawned_threads
129
+ workers.reduce(0) { |total, wstats| total + wstats.spawned_threads }
130
+ end
131
+
126
132
  def max_threads
127
133
  workers.reduce(0) { |total, wstats| total + wstats.max_threads }
128
134
  end
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma-status
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.0'
4
+ version: '1.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoann Lecuyer
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2019-07-14 00:00:00.000000000 Z
@@ -94,8 +94,8 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0.9'
97
- description:
98
- email:
97
+ description:
98
+ email:
99
99
  executables:
100
100
  - puma-status
101
101
  extensions: []
@@ -111,7 +111,7 @@ homepage: https://github.com/ylecuyer/puma-status
111
111
  licenses:
112
112
  - MIT
113
113
  metadata: {}
114
- post_install_message:
114
+ post_install_message:
115
115
  rdoc_options: []
116
116
  require_paths:
117
117
  - lib
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  version: '0'
128
128
  requirements: []
129
129
  rubygems_version: 3.0.0
130
- signing_key:
130
+ signing_key:
131
131
  specification_version: 4
132
132
  summary: Command-line tool for puma to display information about running request/process
133
133
  test_files: []