opentelemetry-instrumentation-httpx 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f48b37a6804e254fb9d9b7a6e039410d332be2652460c17574be592ac501283c
4
- data.tar.gz: df74d2c9904a866aec5b33947ad9acef4efb147630cd28f7ad7716e0a41ad115
3
+ metadata.gz: 30bf96ab2ff772a00b7bf0d1a0be504223461df614db85924f27ceb05174cef1
4
+ data.tar.gz: b291ae28f4cc9d2d62f7ba98648fa70d1d122c204646bdb084f0be864940d552
5
5
  SHA512:
6
- metadata.gz: 81c4c857388e3d9784d9016d7d6726ce863c8672aeaf8d3f3b79da244c988fd5e0fe876fadca68743f4d8a3239747f8f7850475b88bd8360ec1dfa655aea002f
7
- data.tar.gz: 74de494374914328be9861f8f32191609c0931f0e295afb41dc4fb653716d4bf419fd5fa140a0ca598f0a276d173de4598528ec44f2896da32fdeb0e76c8cebc
6
+ metadata.gz: 16ca1e7c26803cdca094cebb24ee417e55c2c07d3cffafd0ae438c6b5260a67662a6c77d6a88732a7a26990ea7fcae2d534441b00bfa972cd6e74bfb39b04fd4
7
+ data.tar.gz: e1d69f6302e2773db472ca4c4053038866af2d8cb4838481c8fbe806af97e9276fc2ab90e9b91505e2d37c2f2d7afb6082557975a033c4d237be03e0655e0fd6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Release History: opentelemetry-instrumentation-httpx
2
2
 
3
+ ### v0.2.1 / 2025-04-29
4
+
5
+ * FIXED: Httpx instrumentation trace context propagation
6
+
3
7
  ### v0.2.0 / 2025-01-16
4
8
 
5
9
  * BREAKING CHANGE: Set minimum supported version to Ruby 3.1
@@ -10,83 +10,114 @@ module OpenTelemetry
10
10
  module Plugin
11
11
  # Instruments around HTTPX's request/response lifecycle in order to generate
12
12
  # an OTEL trace.
13
- class RequestTracer
14
- # Constant for the HTTP status range
15
- HTTP_STATUS_SUCCESS_RANGE = (100..399)
13
+ module RequestTracer
14
+ module_function
15
+
16
+ # initializes tracing on the +request+.
17
+ def call(request)
18
+ span = nil
19
+
20
+ # request objects are reused, when already buffered requests get rerouted to a different
21
+ # connection due to connection issues, or when they already got a response, but need to
22
+ # be retried. In such situations, the original span needs to be extended for the former,
23
+ # while a new is required for the latter.
24
+ request.on(:idle) do
25
+ span = nil
26
+ end
27
+ # the span is initialized when the request is buffered in the parser, which is the closest
28
+ # one gets to actually sending the request.
29
+ request.on(:headers) do
30
+ next if span
31
+
32
+ span = initialize_span(request)
33
+ end
34
+
35
+ request.on(:response) do |response|
36
+ unless span
37
+ next unless response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)
16
38
 
17
- def initialize(request)
18
- @request = request
39
+ # handles the case when the +error+ happened during name resolution, which means
40
+ # that the tracing start point hasn't been triggered yet; in such cases, the approximate
41
+ # initial resolving time is collected from the connection, and used as span start time,
42
+ # and the tracing object in inserted before the on response callback is called.
43
+ span = initialize_span(request, response.error.connection.init_time)
44
+
45
+ end
46
+
47
+ finish(response, span)
48
+ end
19
49
  end
20
50
 
21
- def call
22
- @request.on(:response, &method(:finish)) # rubocop:disable Performance/MethodObjectAsBlock
51
+ def finish(response, span)
52
+ if response.is_a?(::HTTPX::ErrorResponse)
53
+ span.record_exception(response.error)
54
+ span.status = Trace::Status.error(response.error.to_s)
55
+ else
56
+ span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response.status)
57
+
58
+ if response.status.between?(400, 599)
59
+ err = ::HTTPX::HTTPError.new(response)
60
+ span.record_exception(err)
61
+ span.status = Trace::Status.error(err.to_s)
62
+ end
63
+ end
23
64
 
24
- uri = @request.uri
25
- request_method = @request.verb
26
- span_name = "HTTP #{request_method}"
65
+ span.finish
66
+ end
67
+
68
+ # return a span initialized with the +@request+ state.
69
+ def initialize_span(request, start_time = ::Time.now)
70
+ verb = request.verb
71
+ uri = request.uri
72
+
73
+ config = HTTPX::Instrumentation.instance.config
27
74
 
28
75
  attributes = {
29
76
  OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => uri.host,
30
- OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_method,
77
+ OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => verb,
31
78
  OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme,
32
79
  OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path,
33
80
  OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "#{uri.scheme}://#{uri.host}",
34
81
  OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host,
35
82
  OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port
36
83
  }
37
- config = HTTPX::Instrumentation.instance.config
38
- attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service]
39
- attributes.merge!(
40
- OpenTelemetry::Common::HTTP::ClientContext.attributes
41
- )
42
84
 
43
- @span = tracer.start_span(span_name, attributes: attributes, kind: :client)
44
- trace_ctx = OpenTelemetry::Trace.context_with_span(@span)
45
- @trace_token = OpenTelemetry::Context.attach(trace_ctx)
46
-
47
- OpenTelemetry.propagation.inject(@request.headers)
48
- rescue StandardError => e
49
- OpenTelemetry.handle_error(exception: e)
50
- end
85
+ attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service]
86
+ attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
51
87
 
52
- def finish(response)
53
- return unless @span
88
+ span = tracer.start_span("HTTP #{verb}", attributes: attributes, kind: :client, start_timestamp: start_time)
54
89
 
55
- if response.is_a?(::HTTPX::ErrorResponse)
56
- @span.record_exception(response.error)
57
- @span.status = Trace::Status.error("Unhandled exception of type: #{response.error.class}")
58
- else
59
- @span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response.status)
60
- @span.status = Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response.status)
90
+ OpenTelemetry::Trace.with_span(span) do
91
+ OpenTelemetry.propagation.inject(request.headers)
61
92
  end
62
93
 
63
- OpenTelemetry::Context.detach(@trace_token) if @trace_token
64
- @span.finish
94
+ span
95
+ rescue StandardError => e
96
+ OpenTelemetry.handle_error(exception: e)
65
97
  end
66
98
 
67
- private
68
-
69
99
  def tracer
70
100
  HTTPX::Instrumentation.instance.tracer
71
101
  end
72
102
  end
73
103
 
74
- # HTTPX::Request overrides
104
+ # Request patch to initiate the trace on initialization.
75
105
  module RequestMethods
76
- def __otel_enable_trace!
77
- return if @__otel_enable_trace
106
+ def initialize(*)
107
+ super
78
108
 
79
- RequestTracer.new(self).call
80
- @__otel_enable_trace = true
109
+ RequestTracer.call(self)
81
110
  end
82
111
  end
83
112
 
84
- # HTTPX::Connection overrides
113
+ # Connection patch to start monitoring on initialization.
85
114
  module ConnectionMethods
86
- def send(request)
87
- request.__otel_enable_trace!
115
+ attr_reader :init_time
88
116
 
117
+ def initialize(*)
89
118
  super
119
+
120
+ @init_time = ::Time.now
90
121
  end
91
122
  end
92
123
  end
@@ -7,7 +7,7 @@
7
7
  module OpenTelemetry
8
8
  module Instrumentation
9
9
  module HTTPX
10
- VERSION = '0.2.0'
10
+ VERSION = '0.2.1'
11
11
  end
12
12
  end
13
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opentelemetry-instrumentation-httpx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenTelemetry Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-16 00:00:00.000000000 Z
11
+ date: 2025-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -38,174 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.23.0
41
- - !ruby/object:Gem::Dependency
42
- name: appraisal
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '2.5'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '2.5'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.4'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.4'
69
- - !ruby/object:Gem::Dependency
70
- name: minitest
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '5.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '5.0'
83
- - !ruby/object:Gem::Dependency
84
- name: opentelemetry-sdk
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '1.1'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '1.1'
97
- - !ruby/object:Gem::Dependency
98
- name: opentelemetry-test-helpers
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '0.3'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '0.3'
111
- - !ruby/object:Gem::Dependency
112
- name: rake
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '13.0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '13.0'
125
- - !ruby/object:Gem::Dependency
126
- name: rspec-mocks
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- - !ruby/object:Gem::Dependency
140
- name: rubocop
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: 1.69.1
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: 1.69.1
153
- - !ruby/object:Gem::Dependency
154
- name: rubocop-performance
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: 1.23.0
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: 1.23.0
167
- - !ruby/object:Gem::Dependency
168
- name: simplecov
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: 0.17.1
174
- type: :development
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: 0.17.1
181
- - !ruby/object:Gem::Dependency
182
- name: webmock
183
- requirement: !ruby/object:Gem::Requirement
184
- requirements:
185
- - - "~>"
186
- - !ruby/object:Gem::Version
187
- version: 3.24.0
188
- type: :development
189
- prerelease: false
190
- version_requirements: !ruby/object:Gem::Requirement
191
- requirements:
192
- - - "~>"
193
- - !ruby/object:Gem::Version
194
- version: 3.24.0
195
- - !ruby/object:Gem::Dependency
196
- name: yard
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - "~>"
200
- - !ruby/object:Gem::Version
201
- version: '0.9'
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - "~>"
207
- - !ruby/object:Gem::Version
208
- version: '0.9'
209
41
  description: HTTPX instrumentation for the OpenTelemetry framework
210
42
  email:
211
43
  - cncf-opentelemetry-contributors@lists.cncf.io
@@ -227,10 +59,10 @@ homepage: https://github.com/open-telemetry/opentelemetry-ruby-contrib
227
59
  licenses:
228
60
  - Apache-2.0
229
61
  metadata:
230
- changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.2.0/file/CHANGELOG.md
62
+ changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.2.1/file/CHANGELOG.md
231
63
  source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/http
232
64
  bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues
233
- documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.2.0
65
+ documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.2.1
234
66
  post_install_message:
235
67
  rdoc_options: []
236
68
  require_paths: