Skip to content

Instantly share code, notes, and snippets.

@electron0zero
Last active May 8, 2021 16:34
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 electron0zero/436c2ae60dfeb1b0bc347a1fda2ceb3f to your computer and use it in GitHub Desktop.
Save electron0zero/436c2ae60dfeb1b0bc347a1fda2ceb3f to your computer and use it in GitHub Desktop.
Puma Plugin for getting puma stats

Puma Stats Logger - plugin for collecting puma metrics

to configure this plugin, add following in your puma.rb

# plugin to send server stats to our monitoring systems
# export SERVER_STATS_FREQUENCY (seconds) to control the frequency
plugin :stats_logger

NOTE: we keep plugin in lib/puma/plugin/stats_logger.rb, IIRC it is required because of the way puma loads plugins

Update: also checkout https://github.com/harmjanblok/puma-metrics if you are looking for prom metrics

# frozen_string_literal: true
# Puma plugin for sending puma and db connection stats to our monitoring systems
# Taken from: https://gist.github.com/LeZuse/022c501143a5bc4b51a601ad2a1b8abc
# See: https://github.com/puma/puma/issues/1512 to know more about these metrics
# Docs: https://github.com/puma/puma/blob/master/docs/plugins.md
require 'puma/plugin'
Puma::Plugin.create do
# return true if you want to send stats
# return false if you want to disable this plugin
def send_stats?
# do not send stats on development test and beta
env = Rails.env
return false if %w[development test beta].include?(env)
# send stats
return true
end
def start(_launcher)
return unless send_stats?
in_background do
stat_frequency = ENV.fetch('SERVER_STATS_FREQUENCY', 10).to_i
Rails.logger.warn("Sending server stats every #{stat_frequency} seconds")
loop do
sleep(stat_frequency)
begin
all_stats = {}
puma_stats = []
db_pool_stats = []
# Puma.stats: {
# 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,
# }
stats = JSON.parse(Puma.stats, symbolize_names: true)
# get puma stats
if stats[:worker_status].present?
# in cluster mode, get stats from each worker
# stats[:worker_status]: List of workers with their corresponding
# statuses
stats[:worker_status].each do |worker|
# worker[:last_status]: { "backlog":0,"running":2,
# "pool_capacity":2,"max_threads":2 }
stat = worker[:last_status]
puma_stats << stat
end
else
puma_stats << stats
end
# get db pool stats
db_stat = ActiveRecord::Base.connection_pool.stat
# checkout_timeout is sometimes float, make int to make sure events
# are not dropped by InfluxDB
db_stat[:checkout_timeout] = db_stat[:checkout_timeout].to_i
db_pool_stats << db_stat
# build final stats hash
all_stats['puma'] = puma_stats
all_stats['db_pool'] = db_pool_stats
# this call sends it to monitoring system
ServerMetrics.push_stats(all_stats)
rescue StandardError => e
Rails.logger.warn(e)
ensure
# flush logger
Rails.logger.flush
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment