Add basic server status page at /status.

Lists versions of various dependencies plus some Postgres and Redis
metrics.
This commit is contained in:
evazion
2020-12-17 03:05:27 -06:00
parent ee4516f5fe
commit 7a87225ac8
5 changed files with 170 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
class StatusController < ApplicationController
respond_to :html, :json, :xml
def show
@status = ServerStatus.new
respond_with(@status)
end
end

View File

@@ -0,0 +1,109 @@
class ServerStatus
extend Memoist
include ActiveModel::Serializers::JSON
include ActiveModel::Serializers::Xml
def serializable_hash(*options)
{
status: {
hostname: hostname,
uptime: uptime,
loadavg: loadavg,
ruby_version: RUBY_VERSION,
distro_version: distro_version,
kernel_version: kernel_version,
libvips_version: libvips_version,
ffmpeg_version: ffmpeg_version,
mkvmerge_version: mkvmerge_version,
redis_version: redis_version,
postgres_version: postgres_version,
},
postgres: {
connection_stats: postgres_connection_stats,
},
redis: {
info: redis_info,
}
}
end
concerning :InfoMethods do
def hostname
Socket.gethostname
end
def uptime
seconds = File.read("/proc/uptime").split[0].to_f
"#{seconds.seconds.in_days.round} days"
end
def loadavg
File.read("/proc/loadavg").chomp
end
def kernel_version
File.read("/proc/version").chomp
end
def distro_version
`source /etc/os-release; echo "$NAME $VERSION"`.chomp
end
def libvips_version
Vips::LIBRARY_VERSION
end
def ffmpeg_version
version = `ffmpeg -version`
version[/ffmpeg version ([0-9.]+)/, 1]
end
def mkvmerge_version
`mkvmerge --version`.chomp
end
end
concerning :RedisMethods do
def redis_info
return {} if Rails.cache.try(:redis).nil?
Rails.cache.redis.info
end
def redis_used_memory
redis_info["used_memory_rss_human"]
end
def redis_version
redis_info["redis_version"]
end
end
concerning :PostgresMethods do
def postgres_version
ApplicationRecord.connection.select_value("SELECT version()")
end
def postgres_active_connections
ApplicationRecord.connection.select_value("SELECT COUNT(*) FROM pg_stat_activity WHERE state = 'active'")
end
def postgres_connection_stats
run_query("SELECT pid, state, query_start, state_change, xact_start, backend_start, backend_type FROM pg_stat_activity ORDER BY state, query_start DESC, backend_type")
end
def run_query(query)
result = ApplicationRecord.connection.select_all(query)
serialize_result(result)
end
def serialize_result(result)
result.rows.map do |row|
row.each_with_index.map do |col, i|
[result.columns[i], col]
end.to_h
end
end
end
memoize :redis_info
end

View File

@@ -0,0 +1,32 @@
<div id="c-status">
<div id="a-show" class="fixed-width-container">
<h1>Status</h1>
<details>
<summary>
Server: <%= @status.hostname %>
</summary>
<%= render "list", hash: @status.serializable_hash[:status] %>
</details>
<h1>Postgres</h1>
<details>
<summary>
<%= pluralize @status.postgres_active_connections, "active connection" %>.
</summary>
<%= render "table", rows: @status.serializable_hash[:postgres][:connection_stats] %>
</details>
<h1>Redis</h1>
<details>
<summary>
<%= @status.redis_used_memory %> memory used.
</summary>
<%= render "list", hash: @status.serializable_hash[:redis][:info] %>
</details>
</div>
</div>

View File

@@ -227,6 +227,7 @@ Rails.application.routes.draw do
get :sign_out, on: :collection
end
resource :source, :only => [:show]
resource :status, only: [:show], controller: "status"
resources :tags do
collection do
get :autocomplete

View File

@@ -0,0 +1,20 @@
require 'test_helper'
class StatusControllerTest < ActionDispatch::IntegrationTest
context "The status controller" do
should "work for a html response" do
get status_path
assert_response :success
end
should "work for a json response" do
get status_path(format: :json)
assert_response :success
end
should "work for an xml response" do
get status_path(format: :json)
assert_response :success
end
end
end