Module: HTTPX::Plugins::Sentry::Tracer

Defined in:
lib/httpx/adapters/sentry.rb

Class Method Summary collapse

Class Method Details

.call(request) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'lib/httpx/adapters/sentry.rb', line 10

def call(request)
  sentry_span = start_sentry_span

  return unless sentry_span

  set_sentry_trace_header(request, sentry_span)

  request.on(:response, &method(:finish_sentry_span).curry(3)[sentry_span, request])
end

.extract_request_info(req) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/httpx/adapters/sentry.rb', line 79

def extract_request_info(req)
  uri = req.uri

  result = {
    method: req.verb,
  }

  if ::Sentry.configuration.send_default_pii
    uri += "?#{req.query}" unless req.query.empty?
    result[:body] = req.body.to_s unless req.body.empty? || req.body.unbounded_body?
  end

  result[:url] = uri.to_s

  result
end

.finish_sentry_span(span, request, response) ⇒ Object



39
40
41
42
43
44
# File 'lib/httpx/adapters/sentry.rb', line 39

def finish_sentry_span(span, request, response)
  return unless ::Sentry.initialized?

  record_sentry_breadcrumb(request, response)
  record_sentry_span(request, response, span)
end

.record_sentry_breadcrumb(req, res) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/httpx/adapters/sentry.rb', line 46

def record_sentry_breadcrumb(req, res)
  return unless ::Sentry.configuration.breadcrumbs_logger.include?(:http_logger)

  request_info = extract_request_info(req)

  data = if res.is_a?(HTTPX::ErrorResponse)
    { error: res.error.message, **request_info }
  else
    { status: res.status, **request_info }
  end

  crumb = ::Sentry::Breadcrumb.new(
    level: :info,
    category: "httpx",
    type: :info,
    data: data
  )
  ::Sentry.add_breadcrumb(crumb)
end

.record_sentry_span(req, res, sentry_span) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/httpx/adapters/sentry.rb', line 66

def record_sentry_span(req, res, sentry_span)
  return unless sentry_span

  request_info = extract_request_info(req)
  sentry_span.set_description("#{request_info[:method]} #{request_info[:url]}")
  if res.is_a?(HTTPX::ErrorResponse)
    sentry_span.set_data(:error, res.error.message)
  else
    sentry_span.set_data(:status, res.status)
  end
  sentry_span.set_timestamp(::Sentry.utc_now.to_f)
end

.set_sentry_trace_header(request, sentry_span) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/httpx/adapters/sentry.rb', line 27

def set_sentry_trace_header(request, sentry_span)
  return unless sentry_span

  config = ::Sentry.configuration
  url = request.uri.to_s

  return unless config.propagate_traces && config.trace_propagation_targets.any? { |target| url.match?(target) }

  trace = ::Sentry.get_current_client.generate_sentry_trace(sentry_span)
  request.headers[::Sentry::SENTRY_TRACE_HEADER_NAME] = trace if trace
end

.start_sentry_spanObject



20
21
22
23
24
25
# File 'lib/httpx/adapters/sentry.rb', line 20

def start_sentry_span
  return unless ::Sentry.initialized? && (span = ::Sentry.get_current_scope.get_span)
  return if span.sampled == false

  span.start_child(op: "httpx.client", start_timestamp: ::Sentry.utc_now.to_f)
end