Skip to content

Commit

Permalink
Merge pull request #197 from mlibrary/prometheus-metrics
Browse files Browse the repository at this point in the history
Adding prometheus metrics
  • Loading branch information
bertrama authored Nov 19, 2024
2 parents a74d725 + b33f4ab commit c69a5ef
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 37 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ ENV RAILS_RELATIVE_URL_ROOT=${BASE_URL}/spectrum \
BIND_IP=${BIND_IP} \
BIND_PORT=${BIND_PORT}

CMD bundle exec rails s -b ${BIND_IP} -p ${BIND_PORT}
CMD bundle exec puma -c config/puma.rb
6 changes: 5 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ gem "json"
gem "httpclient"
gem "nokogiri"

# HTML replacement language
group :yabeda do
gem "yabeda-puma-plugin"
gem "yabeda-prometheus"
gem "prometheus-client", require: "prometheus/middleware/collector"
end

# "Rack middleware which cleans up invalid UTF8 characters"
# gem 'rack-utf8_sanitizer'
Expand Down
23 changes: 22 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ GEM
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
aes_key_wrap (1.1.0)
anyway_config (2.6.4)
ruby-next-core (~> 1.0)
ast (2.4.2)
attr_required (1.0.2)
base64 (0.2.0)
Expand All @@ -110,6 +112,7 @@ GEM
down (5.4.2)
addressable (~> 2.8)
drb (2.2.1)
dry-initializer (3.1.1)
email_validator (2.2.4)
activemodel
erb (4.0.4)
Expand Down Expand Up @@ -181,7 +184,7 @@ GEM
timeout
net-smtp (0.5.0)
net-protocol
nio4r (2.7.3)
nio4r (2.7.4)
nokogiri (1.16.7)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
Expand Down Expand Up @@ -212,6 +215,8 @@ GEM
ast (~> 2.4.1)
racc
parslet (2.0.0)
prometheus-client (4.2.3)
base64
pry (0.14.2)
coderay (~> 1.1)
method_source (~> 1.0)
Expand Down Expand Up @@ -279,6 +284,7 @@ GEM
rubocop-performance (1.21.1)
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0)
ruby-next-core (1.0.3)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
scrub_rb (1.0.1)
Expand Down Expand Up @@ -341,6 +347,18 @@ GEM
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
yabeda (0.13.1)
anyway_config (>= 1.0, < 3)
concurrent-ruby
dry-initializer
yabeda-prometheus (0.9.1)
prometheus-client (>= 3.0, < 5.0)
rack
yabeda (~> 0.10)
yabeda-puma-plugin (0.7.1)
json
puma
yabeda (~> 0.5)

PLATFORMS
ruby
Expand All @@ -363,6 +381,7 @@ DEPENDENCIES
omniauth_openid_connect
ostruct
parslet
prometheus-client
pry
pry-byebug
puma
Expand All @@ -380,6 +399,8 @@ DEPENDENCIES
standard
twilio-ruby
webmock
yabeda-prometheus
yabeda-puma-plugin

BUNDLED WITH
2.5.16
7 changes: 5 additions & 2 deletions config.ru
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ File.expand_path("lib", __dir__).tap do |libdir|
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
end

ENV['APP_ENV'] ||= ENV['RAILS_ENV']
ENV["APP_ENV"] ||= ENV["RAILS_ENV"]

if ENV["PROMETHEUS_EXPORTER_URL"]
use Prometheus::Middleware::Collector
end

require "bundler"
Bundler.require
Spectrum::Json.configure(__dir__, ENV["RAILS_RELATIVE_URL_ROOT"])

Expand Down
125 changes: 97 additions & 28 deletions config/puma.rb
Original file line number Diff line number Diff line change
@@ -1,44 +1,113 @@
require 'dotenv'
Dotenv.load(File.expand_path('../../.env', __FILE__))
require "dotenv"
Dotenv.load(File.expand_path("../../.env", __FILE__))

ENV['RAILS_RELATIVE_URL_ROOT'] ||= 'http://localhost:3000'
ENV["RAILS_RELATIVE_URL_ROOT"] ||= "http://localhost:3000"

environment 'production'
environment "production"
threads 4, 32

# Use tcp as the http server (apache) is on a different host.
if ENV['PUMA_BIND']
if ENV["PUMA_BIND"]
# If the bind string is in the environment.
bind ENV['PUMA_BIND']
elsif ENV['RAILS_RELATIVE_URL_ROOT'] == 'http://localhost:3000'
bind ENV["PUMA_BIND"]
elsif ENV["RAILS_RELATIVE_URL_ROOT"] == "http://localhost:3000"
# If it's more of a development environment
bind 'tcp://127.0.0.1:3000'
elsif ENV['PUMA_PRIVATE_IP'] && ENV['PUMA_PORT']
bind "tcp://127.0.0.1:3000"
elsif ENV["PUMA_PRIVATE_IP"] && ENV["PUMA_PORT"]
# Bind to the private network address
private_ip = Socket.ip_address_list.find do |ip|
ip.ip_address.start_with?("10.")
end.ip_address
bind "tcp://#{private_ip}:#{ENV['PUMA_PORT']}"
bind "tcp://#{private_ip}:#{ENV["PUMA_PORT"]}"
elsif ENV["BIND_IP"] && ENV["BIND_PORT"]
bind "tcp://#{ENV["BIND_IP"]}:#{ENV["BIND_PORT"]}"
end

pidfile File.expand_path('../../log/search-puma.pid', __FILE__)
pidfile File.expand_path("../../log/search-puma.pid", __FILE__)

on_restart do
# Code to run before doing a restart. This code should
# close log files, database connections, etc.
end
# on_restart do
# Code to run before doing a restart. This code should
# close log files, database connections, etc.
# end

workers ENV['PUMA_WORKERS'] || 2
workers ENV["PUMA_WORKERS"] || 2
worker_timeout 120
#on_worker_boot do
# Code to run when a worker boots to setup the process before booting
#ActiveSupport.on_load(:active_record) do
#ActiveRecord::Base.establish_connection
#end
#end

#before_fork do
#ActiveRecord::Base.connection_pool.disconnect!
#end

activate_control_app ENV['PUMA_CONTROL_APP'], {no_token: true} if ENV['PUMA_CONTROL_APP']
# on_worker_boot do
# Code to run when a worker boots to setup the process before booting
# ActiveSupport.on_load(:active_record) do
# ActiveRecord::Base.establish_connection
# end
# end

# before_fork do
# ActiveRecord::Base.connection_pool.disconnect!
# end

if ENV["PUMA_CONTROL_APP"]
activate_control_app ENV["PUMA_CONTROL_APP"], {no_token: true}

if ENV["PROMETHEUS_EXPORTER_URL"]
Bundler.require :yabeda

plugin :yabeda
plugin :yabeda_prometheus
prometheus_exporter_url ENV["PROMETHEUS_EXPORTER_URL"]

on_worker_boot do
# Prometheus::Middleware::Collector.new has side effects that registers
# metrics. If they are already loaded it raises an exception.
if Prometheus::Client.registry.exist?(:http_server_requests_total)
Prometheus::Client.registry.unregister(:http_server_requests_total)
Prometheus::Client.registry.unregister(:http_server_request_duration_seconds)
Prometheus::Client.registry.unregister(:http_server_exceptions_total)
end

uri = URI(ENV["PROMETHEUS_EXPORTER_URL"])
ObjectSpace.each_object(TCPServer).each do |server|
next if server.closed?
family, port, host, _ = server.addr
if family == "AF_INET" && port == uri.port && host == uri.host
server.close
end
end
end

if (monitoring_dir = ENV["PROMETHEUS_MONITORING_DIR"])
on_prometheus_exporter_boot do
# In clustered mode, the worker processes get these registered, but the coordinating process does not.
# Ending up in these stats being collected, but not reported.
unless Prometheus::Client.registry.exist?(:http_server_requests_total)
# These are copied from Prometheus::Middleware::Collector#init_request_metrics
# and Prometheus::Middleware::Collector#init_exception_metrics
Prometheus::Client.registry.counter(
:http_server_requests_total,
docstring: "The total number of HTTP requests handled by the Rack application.",
labels: %i[code method path]
)
Prometheus::Client.registry.histogram(
:http_server_request_duration_seconds,
docstring: "The HTTP response duration of the Rack application.",
labels: %i[method path]
)
Prometheus::Client.registry.histogram(
:http_server_exceptions_total,
docstring: "The total number of exceptions raised by the Rack application.",
labels: [:exception]
)

Dir[File.join(monitoring_dir, "*.bin")].each do |file_path|
File.unlink(file_path)
end

Yabeda.configure!
end
end

before_fork do
Prometheus::Client.config.data_store =
Prometheus::Client::DataStores::DirectFileStore.new(dir: monitoring_dir)
end
end

end
end
5 changes: 1 addition & 4 deletions script/docker-startup
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@

rm -f tmp/pids/server.pid

bundle exec rackup \
-s "${RAILS_SERVER:-puma}" \
-p "${BIND_PORT}" \
-o "${BIND_IP}"
bundle exec puma -C config/puma.rb

0 comments on commit c69a5ef

Please sign in to comment.