opentelemetry-instrumentation-httpx 0.2.0 → 0.3.0

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: 6c8a1ef0156cbdb24361ce0b786c842a284a5ba882cfa3c9acdd5d1b74774dd2
4
+ data.tar.gz: 06cecad615cba89782a5eda29c1e7d5de1a7af8db5b172b3e9756349d199290e
5
5
  SHA512:
6
- metadata.gz: 81c4c857388e3d9784d9016d7d6726ce863c8672aeaf8d3f3b79da244c988fd5e0fe876fadca68743f4d8a3239747f8f7850475b88bd8360ec1dfa655aea002f
7
- data.tar.gz: 74de494374914328be9861f8f32191609c0931f0e295afb41dc4fb653716d4bf419fd5fa140a0ca598f0a276d173de4598528ec44f2896da32fdeb0e76c8cebc
6
+ metadata.gz: 23b8e7faa82ddfe1f9d7a86a7dd8ec14a7ecb0f651c9a2c6d6ec7c08ea97cdbc1ab74d108ccbc54711ae2bad9c539e8c4e38be05bd1089817860aa7715419475
7
+ data.tar.gz: 0c903889f51a88a7f876712700f7f089e16280d9a459f46c2e86c5f3cd9db856cef079473fef5760e92d805746c288f2f633510380b477cd187988925b3c0078
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Release History: opentelemetry-instrumentation-httpx
2
2
 
3
+ ### v0.3.0 / 2025-08-12
4
+
5
+ * ADDED: HTTPX `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable [#1589](https://github.com/open-telemetry/opentelemetry-ruby-contrib/pull/1589)
6
+
7
+ ### v0.2.1 / 2025-04-29
8
+
9
+ * FIXED: Httpx instrumentation trace context propagation
10
+
3
11
  ### v0.2.0 / 2025-01-16
4
12
 
5
13
  * BREAKING CHANGE: Set minimum supported version to Ruby 3.1
data/README.md CHANGED
@@ -48,3 +48,19 @@ The `opentelemetry-instrumentation-httpx` gem is distributed under the Apache 2.
48
48
  [slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY
49
49
  [discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions
50
50
  [httpx-home]: https://github.com/HoneyryderChuck/httpx
51
+
52
+ ## HTTP semantic convention stability
53
+
54
+ In the OpenTelemetry ecosystem, HTTP semantic conventions have now reached a stable state. However, the initial HTTPX instrumentation was introduced before this stability was achieved, which resulted in HTTP attributes being based on an older version of the semantic conventions.
55
+
56
+ To facilitate the migration to stable semantic conventions, you can use the `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable. This variable allows you to opt-in to the new stable conventions, ensuring compatibility and future-proofing your instrumentation.
57
+
58
+ When setting the value for `OTEL_SEMCONV_STABILITY_OPT_IN`, you can specify which conventions you wish to adopt:
59
+
60
+ - `http` - Emits the stable HTTP and networking conventions and ceases emitting the old conventions previously emitted by the instrumentation.
61
+ - `http/dup` - Emits both the old and stable HTTP and networking conventions, enabling a phased rollout of the stable semantic conventions.
62
+ - Default behavior (in the absence of either value) is to continue emitting the old HTTP and networking conventions the instrumentation previously emitted.
63
+
64
+ During the transition from old to stable conventions, HTTPX instrumentation code comes in three patch versions: `dup`, `old`, and `stable`. These versions are identical except for the attributes they send. Any changes to HTTPX instrumentation should consider all three patches.
65
+
66
+ For additional information on migration, please refer to our [documentation](https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/).
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module Instrumentation
9
+ module HTTPX
10
+ module Dup
11
+ module Plugin
12
+ # Instruments around HTTPX's request/response lifecycle in order to generate
13
+ # an OTEL trace.
14
+ module RequestTracer
15
+ module_function
16
+
17
+ # initializes tracing on the +request+.
18
+ def call(request)
19
+ span = nil
20
+
21
+ # request objects are reused, when already buffered requests get rerouted to a different
22
+ # connection due to connection issues, or when they already got a response, but need to
23
+ # be retried. In such situations, the original span needs to be extended for the former,
24
+ # while a new is required for the latter.
25
+ request.on(:idle) do
26
+ span = nil
27
+ end
28
+ # the span is initialized when the request is buffered in the parser, which is the closest
29
+ # one gets to actually sending the request.
30
+ request.on(:headers) do
31
+ next if span
32
+
33
+ span = initialize_span(request)
34
+ end
35
+
36
+ request.on(:response) do |response|
37
+ unless span
38
+ next unless response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)
39
+
40
+ # handles the case when the +error+ happened during name resolution, which means
41
+ # that the tracing start point hasn't been triggered yet; in such cases, the approximate
42
+ # initial resolving time is collected from the connection, and used as span start time,
43
+ # and the tracing object in inserted before the on response callback is called.
44
+ span = initialize_span(request, response.error.connection.init_time)
45
+
46
+ end
47
+
48
+ finish(response, span)
49
+ end
50
+ end
51
+
52
+ def finish(response, span)
53
+ if response.is_a?(::HTTPX::ErrorResponse)
54
+ span.record_exception(response.error)
55
+ span.status = Trace::Status.error(response.error.to_s)
56
+ else
57
+ span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response.status)
58
+ span.set_attribute('http.response.status_code', response.status)
59
+
60
+ if response.status.between?(400, 599)
61
+ err = ::HTTPX::HTTPError.new(response)
62
+ span.record_exception(err)
63
+ span.status = Trace::Status.error(err.to_s)
64
+ end
65
+ end
66
+
67
+ span.finish
68
+ end
69
+
70
+ # return a span initialized with the +@request+ state.
71
+ def initialize_span(request, start_time = ::Time.now)
72
+ verb = request.verb
73
+ uri = request.uri
74
+
75
+ config = HTTPX::Instrumentation.instance.config
76
+
77
+ attributes = {
78
+ OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => uri.host,
79
+ OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => verb,
80
+ OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme,
81
+ OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path,
82
+ OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "#{uri.scheme}://#{uri.host}",
83
+ OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host,
84
+ OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port,
85
+ 'http.request.method' => verb,
86
+ 'url.scheme' => uri.scheme,
87
+ 'url.path' => uri.path,
88
+ 'url.full' => "#{uri.scheme}://#{uri.host}",
89
+ 'server.address' => uri.host,
90
+ 'server.port' => uri.port
91
+ }
92
+
93
+ attributes['url.query'] = uri.query unless uri.query.nil?
94
+ attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service]
95
+ attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
96
+
97
+ span = tracer.start_span(verb, attributes: attributes, kind: :client, start_timestamp: start_time)
98
+
99
+ OpenTelemetry::Trace.with_span(span) do
100
+ OpenTelemetry.propagation.inject(request.headers)
101
+ end
102
+
103
+ span
104
+ rescue StandardError => e
105
+ OpenTelemetry.handle_error(exception: e)
106
+ end
107
+
108
+ def tracer
109
+ HTTPX::Instrumentation.instance.tracer
110
+ end
111
+ end
112
+
113
+ # Request patch to initiate the trace on initialization.
114
+ module RequestMethods
115
+ def initialize(*)
116
+ super
117
+
118
+ RequestTracer.call(self)
119
+ end
120
+ end
121
+
122
+ # Connection patch to start monitoring on initialization.
123
+ module ConnectionMethods
124
+ attr_reader :init_time
125
+
126
+ def initialize(*)
127
+ super
128
+
129
+ @init_time = ::Time.now
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -10,8 +10,9 @@ module OpenTelemetry
10
10
  # The Instrumentation class contains logic to detect and install the Http instrumentation
11
11
  class Instrumentation < OpenTelemetry::Instrumentation::Base
12
12
  install do |_config|
13
- require_dependencies
14
- patch
13
+ patch_type = determine_semconv
14
+ send(:"require_dependencies_#{patch_type}")
15
+ send(:"patch_#{patch_type}")
15
16
  end
16
17
 
17
18
  compatible do
@@ -24,15 +25,50 @@ module OpenTelemetry
24
25
 
25
26
  option :peer_service, default: nil, validate: :string
26
27
 
27
- def patch
28
- otel_session = ::HTTPX.plugin(Plugin)
28
+ def determine_semconv
29
+ stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', '')
30
+ values = stability_opt_in.split(',').map(&:strip)
31
+
32
+ if values.include?('http/dup')
33
+ 'dup'
34
+ elsif values.include?('http')
35
+ 'stable'
36
+ else
37
+ 'old'
38
+ end
39
+ end
40
+
41
+ def patch_old
42
+ otel_session = ::HTTPX.plugin(Old::Plugin)
29
43
 
30
44
  ::HTTPX.send(:remove_const, :Session)
31
45
  ::HTTPX.send(:const_set, :Session, otel_session.class)
32
46
  end
33
47
 
34
- def require_dependencies
35
- require_relative 'plugin'
48
+ def patch_stable
49
+ otel_session = ::HTTPX.plugin(Stable::Plugin)
50
+
51
+ ::HTTPX.send(:remove_const, :Session)
52
+ ::HTTPX.send(:const_set, :Session, otel_session.class)
53
+ end
54
+
55
+ def patch_dup
56
+ otel_session = ::HTTPX.plugin(Dup::Plugin)
57
+
58
+ ::HTTPX.send(:remove_const, :Session)
59
+ ::HTTPX.send(:const_set, :Session, otel_session.class)
60
+ end
61
+
62
+ def require_dependencies_old
63
+ require_relative 'old/plugin'
64
+ end
65
+
66
+ def require_dependencies_stable
67
+ require_relative 'stable/plugin'
68
+ end
69
+
70
+ def require_dependencies_dup
71
+ require_relative 'dup/plugin'
36
72
  end
37
73
  end
38
74
  end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module Instrumentation
9
+ module HTTPX
10
+ module Old
11
+ module Plugin
12
+ # Instruments around HTTPX's request/response lifecycle in order to generate
13
+ # an OTEL trace.
14
+ module RequestTracer
15
+ module_function
16
+
17
+ # initializes tracing on the +request+.
18
+ def call(request)
19
+ span = nil
20
+
21
+ # request objects are reused, when already buffered requests get rerouted to a different
22
+ # connection due to connection issues, or when they already got a response, but need to
23
+ # be retried. In such situations, the original span needs to be extended for the former,
24
+ # while a new is required for the latter.
25
+ request.on(:idle) do
26
+ span = nil
27
+ end
28
+ # the span is initialized when the request is buffered in the parser, which is the closest
29
+ # one gets to actually sending the request.
30
+ request.on(:headers) do
31
+ next if span
32
+
33
+ span = initialize_span(request)
34
+ end
35
+
36
+ request.on(:response) do |response|
37
+ unless span
38
+ next unless response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)
39
+
40
+ # handles the case when the +error+ happened during name resolution, which means
41
+ # that the tracing start point hasn't been triggered yet; in such cases, the approximate
42
+ # initial resolving time is collected from the connection, and used as span start time,
43
+ # and the tracing object in inserted before the on response callback is called.
44
+ span = initialize_span(request, response.error.connection.init_time)
45
+
46
+ end
47
+
48
+ finish(response, span)
49
+ end
50
+ end
51
+
52
+ def finish(response, span)
53
+ if response.is_a?(::HTTPX::ErrorResponse)
54
+ span.record_exception(response.error)
55
+ span.status = Trace::Status.error(response.error.to_s)
56
+ else
57
+ span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response.status)
58
+
59
+ if response.status.between?(400, 599)
60
+ err = ::HTTPX::HTTPError.new(response)
61
+ span.record_exception(err)
62
+ span.status = Trace::Status.error(err.to_s)
63
+ end
64
+ end
65
+
66
+ span.finish
67
+ end
68
+
69
+ # return a span initialized with the +@request+ state.
70
+ def initialize_span(request, start_time = ::Time.now)
71
+ verb = request.verb
72
+ uri = request.uri
73
+
74
+ config = HTTPX::Instrumentation.instance.config
75
+
76
+ attributes = {
77
+ OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => uri.host,
78
+ OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => verb,
79
+ OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme,
80
+ OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path,
81
+ OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "#{uri.scheme}://#{uri.host}",
82
+ OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host,
83
+ OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port
84
+ }
85
+
86
+ attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service]
87
+ attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
88
+
89
+ span = tracer.start_span("HTTP #{verb}", attributes: attributes, kind: :client, start_timestamp: start_time)
90
+
91
+ OpenTelemetry::Trace.with_span(span) do
92
+ OpenTelemetry.propagation.inject(request.headers)
93
+ end
94
+
95
+ span
96
+ rescue StandardError => e
97
+ OpenTelemetry.handle_error(exception: e)
98
+ end
99
+
100
+ def tracer
101
+ HTTPX::Instrumentation.instance.tracer
102
+ end
103
+ end
104
+
105
+ # Request patch to initiate the trace on initialization.
106
+ module RequestMethods
107
+ def initialize(*)
108
+ super
109
+
110
+ RequestTracer.call(self)
111
+ end
112
+ end
113
+
114
+ # Connection patch to start monitoring on initialization.
115
+ module ConnectionMethods
116
+ attr_reader :init_time
117
+
118
+ def initialize(*)
119
+ super
120
+
121
+ @init_time = ::Time.now
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright The OpenTelemetry Authors
4
+ #
5
+ # SPDX-License-Identifier: Apache-2.0
6
+
7
+ module OpenTelemetry
8
+ module Instrumentation
9
+ module HTTPX
10
+ module Stable
11
+ module Plugin
12
+ # Instruments around HTTPX's request/response lifecycle in order to generate
13
+ # an OTEL trace.
14
+ module RequestTracer
15
+ module_function
16
+
17
+ # initializes tracing on the +request+.
18
+ def call(request)
19
+ span = nil
20
+
21
+ # request objects are reused, when already buffered requests get rerouted to a different
22
+ # connection due to connection issues, or when they already got a response, but need to
23
+ # be retried. In such situations, the original span needs to be extended for the former,
24
+ # while a new is required for the latter.
25
+ request.on(:idle) do
26
+ span = nil
27
+ end
28
+ # the span is initialized when the request is buffered in the parser, which is the closest
29
+ # one gets to actually sending the request.
30
+ request.on(:headers) do
31
+ next if span
32
+
33
+ span = initialize_span(request)
34
+ end
35
+
36
+ request.on(:response) do |response|
37
+ unless span
38
+ next unless response.is_a?(::HTTPX::ErrorResponse) && response.error.respond_to?(:connection)
39
+
40
+ # handles the case when the +error+ happened during name resolution, which means
41
+ # that the tracing start point hasn't been triggered yet; in such cases, the approximate
42
+ # initial resolving time is collected from the connection, and used as span start time,
43
+ # and the tracing object in inserted before the on response callback is called.
44
+ span = initialize_span(request, response.error.connection.init_time)
45
+
46
+ end
47
+
48
+ finish(response, span)
49
+ end
50
+ end
51
+
52
+ def finish(response, span)
53
+ if response.is_a?(::HTTPX::ErrorResponse)
54
+ span.record_exception(response.error)
55
+ span.status = Trace::Status.error(response.error.to_s)
56
+ else
57
+ span.set_attribute('http.response.status_code', response.status)
58
+
59
+ if response.status.between?(400, 599)
60
+ err = ::HTTPX::HTTPError.new(response)
61
+ span.record_exception(err)
62
+ span.status = Trace::Status.error(err.to_s)
63
+ end
64
+ end
65
+
66
+ span.finish
67
+ end
68
+
69
+ # return a span initialized with the +@request+ state.
70
+ def initialize_span(request, start_time = ::Time.now)
71
+ verb = request.verb
72
+ uri = request.uri
73
+
74
+ config = HTTPX::Instrumentation.instance.config
75
+
76
+ attributes = {
77
+ 'http.request.method' => verb,
78
+ 'url.scheme' => uri.scheme,
79
+ 'url.path' => uri.path,
80
+ 'url.full' => "#{uri.scheme}://#{uri.host}",
81
+ 'server.address' => uri.host,
82
+ 'server.port' => uri.port
83
+ }
84
+ attributes['url.query'] = uri.query unless uri.query.nil?
85
+ attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service]
86
+ attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
87
+
88
+ span = tracer.start_span(verb, attributes: attributes, kind: :client, start_timestamp: start_time)
89
+
90
+ OpenTelemetry::Trace.with_span(span) do
91
+ OpenTelemetry.propagation.inject(request.headers)
92
+ end
93
+
94
+ span
95
+ rescue StandardError => e
96
+ OpenTelemetry.handle_error(exception: e)
97
+ end
98
+
99
+ def tracer
100
+ HTTPX::Instrumentation.instance.tracer
101
+ end
102
+ end
103
+
104
+ # Request patch to initiate the trace on initialization.
105
+ module RequestMethods
106
+ def initialize(*)
107
+ super
108
+
109
+ RequestTracer.call(self)
110
+ end
111
+ end
112
+
113
+ # Connection patch to start monitoring on initialization.
114
+ module ConnectionMethods
115
+ attr_reader :init_time
116
+
117
+ def initialize(*)
118
+ super
119
+
120
+ @init_time = ::Time.now
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ 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.3.0'
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.3.0
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-08-14 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
@@ -220,17 +52,19 @@ files:
220
52
  - lib/opentelemetry-instrumentation-httpx.rb
221
53
  - lib/opentelemetry/instrumentation.rb
222
54
  - lib/opentelemetry/instrumentation/httpx.rb
55
+ - lib/opentelemetry/instrumentation/httpx/dup/plugin.rb
223
56
  - lib/opentelemetry/instrumentation/httpx/instrumentation.rb
224
- - lib/opentelemetry/instrumentation/httpx/plugin.rb
57
+ - lib/opentelemetry/instrumentation/httpx/old/plugin.rb
58
+ - lib/opentelemetry/instrumentation/httpx/stable/plugin.rb
225
59
  - lib/opentelemetry/instrumentation/httpx/version.rb
226
60
  homepage: https://github.com/open-telemetry/opentelemetry-ruby-contrib
227
61
  licenses:
228
62
  - Apache-2.0
229
63
  metadata:
230
- changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.2.0/file/CHANGELOG.md
64
+ changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.3.0/file/CHANGELOG.md
231
65
  source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/http
232
66
  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
67
+ documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.3.0
234
68
  post_install_message:
235
69
  rdoc_options: []
236
70
  require_paths:
@@ -1,95 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright The OpenTelemetry Authors
4
- #
5
- # SPDX-License-Identifier: Apache-2.0
6
-
7
- module OpenTelemetry
8
- module Instrumentation
9
- module HTTPX
10
- module Plugin
11
- # Instruments around HTTPX's request/response lifecycle in order to generate
12
- # an OTEL trace.
13
- class RequestTracer
14
- # Constant for the HTTP status range
15
- HTTP_STATUS_SUCCESS_RANGE = (100..399)
16
-
17
- def initialize(request)
18
- @request = request
19
- end
20
-
21
- def call
22
- @request.on(:response, &method(:finish)) # rubocop:disable Performance/MethodObjectAsBlock
23
-
24
- uri = @request.uri
25
- request_method = @request.verb
26
- span_name = "HTTP #{request_method}"
27
-
28
- attributes = {
29
- OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => uri.host,
30
- OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_method,
31
- OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme,
32
- OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path,
33
- OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "#{uri.scheme}://#{uri.host}",
34
- OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host,
35
- OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port
36
- }
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
-
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
51
-
52
- def finish(response)
53
- return unless @span
54
-
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)
61
- end
62
-
63
- OpenTelemetry::Context.detach(@trace_token) if @trace_token
64
- @span.finish
65
- end
66
-
67
- private
68
-
69
- def tracer
70
- HTTPX::Instrumentation.instance.tracer
71
- end
72
- end
73
-
74
- # HTTPX::Request overrides
75
- module RequestMethods
76
- def __otel_enable_trace!
77
- return if @__otel_enable_trace
78
-
79
- RequestTracer.new(self).call
80
- @__otel_enable_trace = true
81
- end
82
- end
83
-
84
- # HTTPX::Connection overrides
85
- module ConnectionMethods
86
- def send(request)
87
- request.__otel_enable_trace!
88
-
89
- super
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end