class PrometheusExporter::Middleware
Constants
- MethodProfiler
Public Class Methods
new(app, config = { instrument: true, client: nil })
click to toggle source
# File lib/prometheus_exporter/middleware.rb, line 9 def initialize(app, config = { instrument: true, client: nil }) @app = app @client = config[:client] || PrometheusExporter::Client.default if config[:instrument] if defined? Redis::Client MethodProfiler.patch(Redis::Client, [:call, :call_pipeline], :redis) end if defined? PG::Connection MethodProfiler.patch(PG::Connection, [ :exec, :async_exec, :exec_prepared, :send_query_prepared, :query ], :sql) end if defined? Mysql2::Client MethodProfiler.patch(Mysql2::Client, [:query], :sql) MethodProfiler.patch(Mysql2::Statement, [:execute], :sql) MethodProfiler.patch(Mysql2::Result, [:each], :sql) end end end
Public Instance Methods
call(env)
click to toggle source
# File lib/prometheus_exporter/middleware.rb, line 30 def call(env) queue_time = measure_queue_time(env) MethodProfiler.start result = @app.call(env) info = MethodProfiler.stop result ensure obj = { type: "web", timings: info, queue_time: queue_time, default_labels: default_labels(env, result) } labels = custom_labels(env) if labels obj = obj.merge(custom_labels: labels) end @client.send_json(obj) end
custom_labels(env)
click to toggle source
allows subclasses to add custom labels based on env
# File lib/prometheus_exporter/middleware.rb, line 71 def custom_labels(env) nil end
default_labels(env, result)
click to toggle source
# File lib/prometheus_exporter/middleware.rb, line 54 def default_labels(env, result) status = (result && result[0]) || -1 params = env["action_dispatch.request.parameters"] action = controller = nil if params action = params["action"] controller = params["controller"] end { action: action || "other", controller: controller || "other", status: status } end
Private Instance Methods
measure_queue_time(env)
click to toggle source
measures the queue time (= time between receiving the request in downstream load balancer and starting request in ruby process)
# File lib/prometheus_exporter/middleware.rb, line 79 def measure_queue_time(env) start_time = queue_start(env) return unless start_time queue_time = request_start.to_f - start_time.to_f queue_time unless queue_time.negative? end
queue_start(env)
click to toggle source
determine queue start from well-known trace headers
# File lib/prometheus_exporter/middleware.rb, line 94 def queue_start(env) # get the content of the x-queue-start or x-request-start header value = env['HTTP_X_REQUEST_START'] || env['HTTP_X_QUEUE_START'] unless value.nil? || value == '' # nginx returns time as milliseconds with 3 decimal places # apache returns time as microseconds without decimal places # this method takes care to convert both into a proper second + fractions timestamp value = value.to_s.gsub(/t=|\./, '') return "#{value[0, 10]}.#{value[10, 13]}".to_f end # get the content of the x-amzn-trace-id header # see also: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-request-tracing.html value = env['HTTP_X_AMZN_TRACE_ID'] value&.split('Root=')&.last&.split('-')&.fetch(1)&.to_i(16) end
request_start()
click to toggle source
need to use CLOCK_REALTIME, as nginx/apache write this also out as the unix timestamp
# File lib/prometheus_exporter/middleware.rb, line 89 def request_start Process.clock_gettime(Process::CLOCK_REALTIME) end