Skip to content

Commit

Permalink
Add Puma.stats_hash
Browse files Browse the repository at this point in the history
Change Puma.stats to Puma.stats_json to help disambiguate. An alias is provided for backwards compatibility

Having access to the hash allows to produce stats in other ways (such as StatsD) without having to parse JSON of data that is available in memory. An example of this workaround is https://github.com/yob/puma-plugin-statsd/blob/fa6ba1f5074473618643ef7cf99747801a001dec/lib/puma/plugin/statsd.rb#L112-L114
  • Loading branch information
bdewater committed Dec 9, 2019
1 parent 75e2179 commit 50c2099
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 18 deletions.
1 change: 1 addition & 0 deletions History.md
Expand Up @@ -3,6 +3,7 @@
* Features
* Add pumactl `thread-backtraces` command to print thread backtraces (#2053)
* Configuration: `environment` is read from `RAILS_ENV`, if `RACK_ENV` can't be found (#2022)
* `Puma.stats` was renamed to `Puma.stats_json`, `Puma.stats_hash` has been added to provide the same data as a Hash

* Bugfixes
* Your bugfix goes here (#Github Number)
Expand Down
10 changes: 8 additions & 2 deletions lib/puma.rb
Expand Up @@ -19,10 +19,16 @@ def self.stats_object=(val)
@get_stats = val
end

def self.stats
@get_stats.stats
def self.stats_hash
@get_stats.stats_hash
end


def self.stats_json
@get_stats.stats_json
end
singleton_class.alias_method :stats, :stats_json

# Thread name is new in Ruby 2.3
def self.set_thread_name(name)
return unless Thread.current.respond_to?(:name=)
Expand Down
2 changes: 1 addition & 1 deletion lib/puma/app/status.rb
Expand Up @@ -54,7 +54,7 @@ def call(env)
rack_response(200, GC.stat.to_json)

when /\/stats$/
rack_response(200, @cli.stats)
rack_response(200, @cli.stats_json)

when /\/thread-backtraces$/
backtraces = []
Expand Down
32 changes: 28 additions & 4 deletions lib/puma/cluster.rb
Expand Up @@ -350,12 +350,36 @@ def reload_worker_directory

# Inside of a child process, this will return all zeroes, as @workers is only populated in
# the master process.
def stats
def stats_hash
old_worker_count = @workers.count { |w| w.phase != @phase }
booted_worker_count = @workers.count { |w| w.booted? }
worker_status = '[' + @workers.map { |w| %Q!{ "started_at": "#{w.started_at.utc.iso8601}", "pid": #{w.pid}, "index": #{w.index}, "phase": #{w.phase}, "booted": #{w.booted?}, "last_checkin": "#{w.last_checkin.utc.iso8601}", "last_status": #{w.last_status} }!}.join(",") + ']'
%Q!{ "started_at": "#{@started_at.utc.iso8601}", "workers": #{@workers.size}, "phase": #{@phase}, "booted_workers": #{booted_worker_count}, "old_workers": #{old_worker_count}, "worker_status": #{worker_status} }!
worker_status = @workers.map do |w|
{
started_at: w.started_at.utc.iso8601,
pid: w.pid,
index: w.index,
phase: w.phase,
booted: w.booted?,
last_checkin: w.last_checkin.utc.iso8601,
last_status: w.last_status,
}
end

{
started_at: @started_at.utc.iso8601,
workers: @workers.size,
phase: @phase,
booted_workers: worker_status.count { |w| w[:booted] },
old_workers: old_worker_count,
worker_status: worker_status,
}
end

def stats_json
h = stats_hash
worker_status = '[' + h[:worker_status].map { |w| %Q!{ "started_at": "#{w[:started_at]}", "pid": #{w[:pid]}, "index": #{w[:index]}, "phase": #{w[:phase]}, "booted": #{w[:booted]}, "last_checkin": "#{w[:last_checkin]}", "last_status": #{w[:last_status]} }!}.join(",") + ']'
%Q!{ "started_at": "#{h[:started_at]}", "workers": #{h[:workers]}, "phase": #{h[:phase]}, "booted_workers": #{h[:booted_workers]}, "old_workers": #{h[:old_workers]}, "worker_status": #{worker_status} }!
end
#alias_method :stats, :stats_json

def preload?
@options[:preload_app]
Expand Down
9 changes: 7 additions & 2 deletions lib/puma/launcher.rb
Expand Up @@ -95,10 +95,15 @@ def initialize(conf, launcher_args={})
attr_reader :binder, :events, :config, :options, :restart_dir

# Return stats about the server
def stats
@runner.stats
def stats_hash
@runner.stats_hash
end

def stats_json
@runner.stats_json
end
alias_method :stats, :stats_json

# Write a state file that can be used by pumactl to control
# the server
def write_state
Expand Down
20 changes: 14 additions & 6 deletions lib/puma/single.rb
Expand Up @@ -13,14 +13,22 @@ module Puma
# gets created via the `start_server` method from the `Puma::Runner` class
# that this inherits from.
class Single < Runner
def stats
b = @server.backlog || 0
r = @server.running || 0
t = @server.pool_capacity || 0
m = @server.max_threads || 0
%Q!{ "started_at": "#{@started_at.utc.iso8601}", "backlog": #{b}, "running": #{r}, "pool_capacity": #{t}, "max_threads": #{m} }!
def stats_hash
{
started_at: @started_at.utc.iso8601,
backlog: @server.backlog || 0,
running: @server.running || 0,
pool_capacity: @server.pool_capacity || 0,
max_threads: @server.max_threads || 0,
}
end

def stats_json
h = stats_hash
%Q!{ "started_at": "#{h[:started_at]}", "backlog": #{h[:backlog]}, "running": #{h[:running]}, "pool_capacity": #{h[:pool_capacity]}, "max_threads": #{h[:max_threads]} }!
end
alias_method :stats, :stats_json

def restart
@server.begin_restart
end
Expand Down
2 changes: 1 addition & 1 deletion test/test_app_status.rb
Expand Up @@ -23,7 +23,7 @@ def halt
@status = :halt
end

def stats
def stats_json
"{}"
end
end
Expand Down
6 changes: 4 additions & 2 deletions test/test_cli.rb
Expand Up @@ -58,7 +58,8 @@ def test_control_for_tcp
s.close

assert_match(/{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/, body.split(/\r?\n/).last)
assert_match(/{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/, Puma.stats)
assert_match(/{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/, Puma.stats_json)
assert_equal([:started_at, :backlog, :running, :pool_capacity, :max_threads], Puma.stats_hash.keys)

ensure
cli.launcher.stop
Expand Down Expand Up @@ -94,7 +95,8 @@ def test_control_for_ssl

expected_stats = /{ "started_at": "\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z", "backlog": 0, "running": 0, "pool_capacity": 16, "max_threads": 16 }/
assert_match(expected_stats, body.split(/\r?\n/).last)
assert_match(expected_stats, Puma.stats)
assert_match(expected_stats, Puma.stats_json)
assert_equal([:started_at, :backlog, :running, :pool_capacity, :max_threads], Puma.stats_hash.keys)

ensure
cli.launcher.stop
Expand Down

0 comments on commit 50c2099

Please sign in to comment.