Skip to content

Instantly share code, notes, and snippets.

@eprothro
Created November 6, 2017 19:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eprothro/a858c732f0c83a596c605bcf69ae15ad to your computer and use it in GitHub Desktop.
Save eprothro/a858c732f0c83a596c605bcf69ae15ad to your computer and use it in GitHub Desktop.
ruby script to print puma worker/fork thread utilization info
require 'puma'
require 'puma/control_cli'
require 'json'
class PumaWorkersPrinter
attr_reader :format
def initialize(opts={})
@format = opts.fetch(:format){ :plain }
@password = opts.fetch(:password){ '' }
@control_url = opts.fetch(:control_url){ 'tcp://127.0.0.1:9293' }
end
def metadata
{
source: "puma"
}
end
# fetch worker info from puma control
# server and print thread utilization
# info for each fork to STDOUT
def run
@workers = nil
workers.each do |worker|
puts formatter.new(metadata.merge(worker)).inspect
end
end
def workers
@workers ||= build_workers
end
protected
def formatter
case format.to_sym
when :json
JsonFormatter
else
SimpleFormatter
end
end
def build_workers
buffer = StringIO.new
command = Puma::ControlCLI.new(
[
'-C', control_url,
'-T', password,
'stats'
],
buffer,
buffer)
command.run
JSON.parse(buffer.string.split("\n").last)["worker_status"]
end
def password
@password
end
def control_url
@control_url
end
class Formatter
attr_accessor :hash
# {
# "pid"=>2249,
# "index"=>0,
# "phase"=>0,
# "booted"=>true,
# "last_checkin"=>"2017-05-09T19:19:44Z",
# "last_status"=>{
# "backlog"=>0,
# "running"=>1
# }
# }
def initialize(hash)
@hash = hash.dup
end
end
class SimpleFormatter < Formatter
def inspect
string = "PID=#{hash['pid']} FORK=#{hash['index']} (\n"
string += " phase #{hash['phase']}\n"
string += " booted #{hash['booted']}\n"
string += " last_updated #{ago(hash['last_checkin'])} ms ago\n"
string += " running #{hash['last_status']['running']}\n"
string += " backlog #{hash['last_status']['backlog']}\n"
end
def ago(iso_time)
((Time.now - Time.parse(iso_time)) * 1000).round(0)
end
end
class JsonFormatter < Formatter
def inspect
flattened.to_json
end
def flattened
hash.merge!(hash.delete('last_status'))
hash.merge!({'fork' => hash.delete('index')})
hash
end
end
end
opts = {format: :json, password: 'foo'}
PumaWorkersPrinter.new(opts).run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment