sentry-ruby/lib/sentry/faraday.rb
# frozen_string_literal: true
module Sentry
module Faraday
OP_NAME = "http.client"
module Connection
# Since there's no way to preconfigure Faraday connections and add our instrumentation
# by default, we need to extend the connection constructor and do it there
#
# @see https://lostisland.github.io/faraday/#/customization/index?id=configuration
def initialize(url = nil, options = nil)
super
# Ensure that we attach instrumentation only if the adapter is not net/http
# because if is is, then the net/http instrumentation will take care of it
if builder.adapter.name != "Faraday::Adapter::NetHttp"
# Make sure that it's going to be the first middleware so that it can capture
# the entire request processing involving other middlewares
builder.insert(0, ::Faraday::Request::Instrumentation, name: OP_NAME, instrumenter: Instrumenter.new)
end
end
end
class Instrumenter
SPAN_ORIGIN = "auto.http.faraday"
BREADCRUMB_CATEGORY = "http"
include Utils::HttpTracing
def instrument(op_name, env, &block)
return block.call unless Sentry.initialized?
Sentry.with_child_span(op: op_name, start_timestamp: Sentry.utc_now.to_f, origin: SPAN_ORIGIN) do |sentry_span|
request_info = extract_request_info(env)
if propagate_trace?(request_info[:url])
set_propagation_headers(env[:request_headers])
end
res = block.call
response_status = res.status
if record_sentry_breadcrumb?
record_sentry_breadcrumb(request_info, response_status)
end
if sentry_span
set_span_info(sentry_span, request_info, response_status)
end
res
end
end
private
def extract_request_info(env)
url = env[:url].scheme + "://" + env[:url].host + env[:url].path
result = { method: env[:method].to_s.upcase, url: url }
if Sentry.configuration.send_default_pii
result[:query] = env[:url].query
result[:body] = env[:body]
end
result
end
end
end
end
Sentry.register_patch(:faraday) do
if defined?(::Faraday)
::Faraday::Connection.prepend(Sentry::Faraday::Connection)
end
end