Module: Datadog::Tracing::Contrib::HTTPX::Plugin::RequestTracer

Extended by:
Contrib::HttpAnnotationHelper
Defined in:
lib/httpx/adapters/datadog.rb

Constant Summary collapse

SPAN_REQUEST =
"httpx.request"

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.call(request) ⇒ Object

initializes tracing on the request.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/httpx/adapters/datadog.rb', line 46

def call(request)
  return unless configuration(request).enabled

  span = nil

  # request objects are reused, when already buffered requests get rerouted to a different
  # connection due to connection issues, or when they already got a response, but need to
  # be retried. In such situations, the original span needs to be extended for the former,
  # while a new is required for the latter.
  request.on(:idle) do
    span = nil
  end
  # the span is initialized when the request is buffered in the parser, which is the closest
  # one gets to actually sending the request.
  request.on(:headers) do
    next if span

    span = initialize_span(request, now)
  end

  request.on(:response) do |response|
    unless span
      next unless response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)

      # handles the case when the +error+ happened during name resolution, which means
      # that the tracing start point hasn't been triggered yet; in such cases, the approximate
      # initial resolving time is collected from the connection, and used as span start time,
      # and the tracing object in inserted before the on response callback is called.
      span = initialize_span(request, response.error.connection.init_time)

    end

    finish(response, span)
  end
end

.configuration(request) ⇒ Object



154
155
156
# File 'lib/httpx/adapters/datadog.rb', line 154

def configuration(request)
  Datadog.configuration.tracing[:httpx, request.uri.host]
end

.finish(response, span) ⇒ Object



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/httpx/adapters/datadog.rb', line 82

def finish(response, span)
  if response.is_a?(::HTTPX::ErrorResponse)
    span.set_error(response.error)
  else
    span.set_tag(TAG_STATUS_CODE, response.status.to_s)

    span.set_error(::HTTPX::HTTPError.new(response)) if response.status >= 400 && response.status <= 599

    span.set_tags(
      Datadog.configuration.tracing.header_tags.response_tags(response.headers.to_h)
    )
  end

  span.finish
end

.initialize_span(request, start_time) ⇒ Object

return a span initialized with the @request state.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/httpx/adapters/datadog.rb', line 99

def initialize_span(request, start_time)
  verb = request.verb
  uri = request.uri

  config = configuration(request)

  span = create_span(request, config, start_time)

  span.resource = verb

  # Tag original global service name if not used
  span.set_tag(TAG_BASE_SERVICE, Datadog.configuration.service) if span.service != Datadog.configuration.service

  span.set_tag(TAG_KIND, TAG_CLIENT)

  span.set_tag(TAG_COMPONENT, "httpx")
  span.set_tag(TAG_OPERATION, "request")

  span.set_tag(TAG_URL, request.path)
  span.set_tag(TAG_METHOD, verb)

  span.set_tag(TAG_TARGET_HOST, uri.host)
  span.set_tag(TAG_TARGET_PORT, uri.port)

  span.set_tag(TAG_PEER_HOSTNAME, uri.host)

  # Tag as an external peer service
  # span.set_tag(TAG_PEER_SERVICE, span.service)

  if config[:distributed_tracing]
    propagate_trace_http(
      Datadog::Tracing.active_trace,
      request.headers
    )
  end

  # Set analytics sample rate
  if Contrib::Analytics.enabled?(config[:analytics_enabled])
    Contrib::Analytics.set_sample_rate(span, config[:analytics_sample_rate])
  end

  span.set_tags(
    Datadog.configuration.tracing.header_tags.request_tags(request.headers.to_h)
  )

  span
rescue StandardError => e
  Datadog.logger.error("error preparing span for http request: #{e}")
  Datadog.logger.error(e.backtrace)
end

.nowObject



150
151
152
# File 'lib/httpx/adapters/datadog.rb', line 150

def now
  ::Datadog::Core::Utils::Time.now.utc
end

Instance Method Details

#create_span(request, configuration, start_time) ⇒ Object



163
164
165
166
167
168
169
170
# File 'lib/httpx/adapters/datadog.rb', line 163

def create_span(request, configuration, start_time)
  Datadog::Tracing.trace(
    SPAN_REQUEST,
    service: service_name(request.uri.host, configuration),
    type: TYPE_OUTBOUND,
    start_time: start_time
  )
end

#propagate_trace_http(trace, headers) ⇒ Object



159
160
161
# File 'lib/httpx/adapters/datadog.rb', line 159

def propagate_trace_http(trace, headers)
  Datadog::Tracing::Contrib::HTTP.inject(trace, headers)
end