1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
# frozen_string_literal: true
module HTTP
module Features
# Instrument requests and responses. Expects an
# ActiveSupport::Notifications-compatible instrumenter. Defaults to use a
# namespace of 'http' which may be overridden with a `:namespace` param.
# Emits a single event like `"request.{namespace}"`, eg `"request.http"`.
# Be sure to specify the instrumenter when enabling the feature:
#
# HTTP
# .use(instrumentation: {instrumenter: ActiveSupport::Notifications.instrumenter})
# .get("https://example.com/")
#
# Emits two events on every request:
#
# * `start_request.http` before the request is made, so you can log the reqest being started
# * `request.http` after the response is recieved, and contains `start`
# and `finish` so the duration of the request can be calculated.
#
class Instrumentation < Feature
attr_reader :instrumenter, :name
def initialize(instrumenter: NullInstrumenter.new, namespace: "http")
@instrumenter = instrumenter
@name = "request.#{namespace}"
end
def wrap_request(request)
# Emit a separate "start" event, so a logger can print the request
# being run without waiting for a response
instrumenter.instrument("start_#{name}", :request => request) {}
instrumenter.start(name, :request => request)
request
end
def wrap_response(response)
instrumenter.finish(name, :response => response)
response
end
HTTP::Options.register_feature(:instrumentation, self)
class NullInstrumenter
def instrument(name, payload = {})
start(name, payload)
begin
yield payload if block_given?
ensure
finish name, payload
end
end
def start(_name, _payload)
true
end
def finish(_name, _payload)
true
end
end
end
end
end
|