1
0
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2025-11-30 21:32:30 +00:00

feat: add health server and prometheus metrics to worker

هذا الالتزام موجود في:
Adam Cooke
2024-02-23 18:11:05 +00:00
ملتزم من قبل Adam Cooke
الأصل 1ae8ef6401
التزام a2eb70edf1
7 ملفات معدلة مع 167 إضافات و3 حذوفات

عرض الملف

@@ -0,0 +1,23 @@
# frozen_string_literal: true
module HasPrometheusMetrics
def register_prometheus_counter(name, **kwargs)
counter = Prometheus::Client::Counter.new(name, **kwargs)
registry.register(counter)
end
def increment_prometheus_counter(name, labels: {})
counter = registry.get(name)
return if counter.nil?
counter.increment(labels: labels)
end
private
def registry
Prometheus::Client.registry
end
end

107
app/util/health_server.rb Normal file
عرض الملف

@@ -0,0 +1,107 @@
# frozen_string_literal: true
require "socket"
require "rack/handler/webrick"
require "prometheus/client/formats/text"
class HealthServer
def initialize(name: "unnamed-process")
@name = name
end
def call(env)
case env["PATH_INFO"]
when "/health"
ok
when "/metrics"
metrics
when "/"
root
else
not_found
end
end
private
def root
[200, { "Content-Type" => "text/plain" }, ["#{@name} (pid: #{Process.pid}, host: #{Socket.gethostname})"]]
end
def ok
[200, { "Content-Type" => "text/plain" }, ["OK"]]
end
def not_found
[404, { "Content-Type" => "text/plain" }, ["Not Found"]]
end
def metrics
registry = Prometheus::Client.registry
body = Prometheus::Client::Formats::Text.marshal(registry)
[200, { "Content-Type" => "text/plain" }, [body]]
end
class << self
def run(default_port: 9090, **options)
port = ENV.fetch("HEALTH_SERVER_PORT", default_port)
Rack::Handler::WEBrick.run(new(**options),
Port: port,
BindAddress: bind_address,
AccessLog: [],
Logger: LoggerProxy.new)
rescue Errno::EADDRINUSE
Postal.logger.info "health server port (#{bind_address}:#{port}) is already " \
"in use, not starting health server"
end
def bind_address
ENV.fetch("HEALTH_SERVER_BIND_ADDRESS", "127.0.0.1")
end
def start(**options)
thread = Thread.new { run(**options) }
thread.abort_on_exception = false
thread
end
end
class LoggerProxy
[:info, :debug, :warn, :error, :fatal].each do |severity|
define_method(severity) do |message|
add(severity, message)
end
define_method("#{severity}?") do
severity != :debug
end
end
def add(severity, message)
return if severity == :debug
case message
when /\AWEBrick::HTTPServer#start:.*port=(\d+)/
Postal.logger.info "started health server on port #{::Regexp.last_match(1)}", component: "true"
when /\AWEBrick::HTTPServer#start done/
Postal.logger.info "stopped health server"
when /\AWEBrick [\d.]+/,
/\Aruby ([\d.]+)/,
/\ARack::Handler::WEBrick is mounted/,
/\Aclose TCPSocket/,
/\Agoing to shutdown/
# Don't actually print routine messages to avoid too much
# clutter when processes start it
else
Postal.logger.debug message, component: "true"
end
end
end
end