module Sentry::Net::HTTP

Constants

OP_NAME

Public Instance Methods

do_finish() click to toggle source
Calls superclass method
# File lib/sentry/net/http.rb, line 50
def do_finish
  super.tap do
    finish_sentry_span
  end
end
do_start() click to toggle source
Calls superclass method
# File lib/sentry/net/http.rb, line 44
def do_start
  super.tap do
    start_sentry_span
  end
end
request(req, body = nil, &block) click to toggle source

To explain how the entire thing works, we need to know how the original Net::HTTP#request works Here's part of its definition. As you can see, it usually calls itself inside a start block

“` def request(req, body = nil, &block)

unless started?
  start {
    req['connection'] ||= 'close'
    return request(req, body, &block) # <- request will be called for the second time from the first call
  }
end
# .....

end “`

So when the entire flow looks like this:

  1. request is called.

- But because the request hasn't started yet, it calls #start (which then calls #do_start)
- At this moment @sentry_span is still nil, so #set_sentry_trace_header returns early
  1. do_start then creates a new Span and assigns it to @sentry_span

  2. request is called for the second time.

- This time @sentry_span should present. So #set_sentry_trace_header will set the sentry-trace header on the request object
  1. Once the request finished, it

- Records a breadcrumb if http_logger is set
- Finishes the Span inside @sentry_span and clears the instance variable
Calls superclass method
# File lib/sentry/net/http.rb, line 35
def request(req, body = nil, &block)
  set_sentry_trace_header(req)

  super.tap do |res|
    record_sentry_breadcrumb(req, res)
    record_sentry_span(req, res)
  end
end

Private Instance Methods

extract_request_info(req) click to toggle source
# File lib/sentry/net/http.rb, line 114
def extract_request_info(req)
  uri = req.uri
  url = "#{uri.scheme}://#{uri.host}#{uri.path}" rescue uri.to_s
  { method: req.method, url: url }
end
finish_sentry_span() click to toggle source
# File lib/sentry/net/http.rb, line 102
def finish_sentry_span
  if Sentry.initialized? && @sentry_span
    @sentry_span.set_timestamp(Sentry.utc_now.to_f)
    @sentry_span = nil
  end
end
from_sentry_sdk?() click to toggle source
# File lib/sentry/net/http.rb, line 109
def from_sentry_sdk?
  dsn = Sentry.configuration.dsn
  dsn && dsn.host == self.address
end
record_sentry_breadcrumb(req, res) click to toggle source
# File lib/sentry/net/http.rb, line 65
def record_sentry_breadcrumb(req, res)
  if Sentry.initialized? && Sentry.configuration.breadcrumbs_logger.include?(:http_logger)
    return if from_sentry_sdk?

    request_info = extract_request_info(req)
    crumb = Sentry::Breadcrumb.new(
      level: :info,
      category: OP_NAME,
      type: :info,
      data: {
        method: request_info[:method],
        url: request_info[:url],
        status: res.code.to_i
      }
    )
    Sentry.add_breadcrumb(crumb)
  end
end
record_sentry_span(req, res) click to toggle source
# File lib/sentry/net/http.rb, line 84
def record_sentry_span(req, res)
  if Sentry.initialized? && @sentry_span
    request_info = extract_request_info(req)
    @sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
    @sentry_span.set_data(:status, res.code.to_i)
  end
end
set_sentry_trace_header(req) click to toggle source
# File lib/sentry/net/http.rb, line 58
def set_sentry_trace_header(req)
  return unless @sentry_span

  trace = Sentry.get_current_client.generate_sentry_trace(@sentry_span)
  req[SENTRY_TRACE_HEADER_NAME] = trace if trace
end
start_sentry_span() click to toggle source
# File lib/sentry/net/http.rb, line 92
def start_sentry_span
  if Sentry.initialized? && transaction = Sentry.get_current_scope.get_transaction
    return if from_sentry_sdk?
    return if transaction.sampled == false

    child_span = transaction.start_child(op: OP_NAME, start_timestamp: Sentry.utc_now.to_f)
    @sentry_span = child_span
  end
end