opentelemetry-instrumentation-ethon 0.22.0 → 0.23.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: 5da94e8bf071f770f1bed046b0a7766e14380162d72a6d5e5ed2d32d386aaea2
4
- data.tar.gz: 974c11a490e18fbe95826cd9cb2929d253c7d217baf25d9bc627a9444b51c5f6
3
+ metadata.gz: 8bbbe66773c8fce6953073cbd3abc9ed960cedc72dab5d23b58681f2970b6d1f
4
+ data.tar.gz: 1decc400420cc2a26de71704e789a91dbd1db8a264fb105f1f6cb62bb3f26be6
5
5
  SHA512:
6
- metadata.gz: 0e31a35b06cbb27f95f0a6f07a7198244b6513e640f009ec66a190cae0a4413e2f38219c187cd9ee99675d26a4b329f10f7e91212f90c08d6db3e3b03ac6fc99
7
- data.tar.gz: b3d37196e2a1774e90f50050df1be49966fff0b43cbd2db2513ea0a955c122793a591dc08151fea1e6a95f8f662afe57677a3532c71aa0354376ac8390b57d45
6
+ metadata.gz: 4977551e5520240c119eca62427f21e493b35f48e3033e370517679ad21050187a4352468944f590ee62cc25aaa7e5d55ee51eb239fd457ce5408dcdd0de7493
7
+ data.tar.gz: 6c35ebff6e824bbc848db16c7094906fe2b36d3756583d899164c809b91fe6951c1b74b1095169b96a347b245933e4b6bf8a9fae3507d29d7093111c45d64116
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Release History: opentelemetry-instrumentation-ethon
2
2
 
3
+ ### v0.23.0 / 2025-07-29
4
+
5
+ * ADDED: Add Ethon `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable [#1561](https://github.com/open-telemetry/opentelemetry-ruby-contrib/pull/1561)
6
+
3
7
  ### v0.22.0 / 2025-01-16
4
8
 
5
9
  * BREAKING CHANGE: Set minimum supported version to Ruby 3.1
data/README.md CHANGED
@@ -32,7 +32,7 @@ end
32
32
 
33
33
  ## Examples
34
34
 
35
- Example usage of faraday can be seen in the `./example/ethon.rb` file [here](https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/instrumentation/ethon/example/ethon.rb)
35
+ Example usage of faraday can be seen in the [`./example/ethon.rb` file](https://github.com/open-telemetry/opentelemetry-ruby-contrib/blob/main/instrumentation/ethon/example/ethon.rb)
36
36
 
37
37
  ## How can I get involved?
38
38
 
@@ -52,3 +52,19 @@ The `opentelemetry-instrumentation-all` gem is distributed under the Apache 2.0
52
52
  [community-meetings]: https://github.com/open-telemetry/community#community-meetings
53
53
  [slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY
54
54
  [discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions
55
+
56
+ ## HTTP semantic convention stability
57
+
58
+ In the OpenTelemetry ecosystem, HTTP semantic conventions have now reached a stable state. However, the initial Ethon instrumentation was introduced before this stability was achieved, which resulted in HTTP attributes being based on an older version of the semantic conventions.
59
+
60
+ 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.
61
+
62
+ When setting the value for `OTEL_SEMCONV_STABILITY_OPT_IN`, you can specify which conventions you wish to adopt:
63
+
64
+ - `http` - Emits the stable HTTP and networking conventions and ceases emitting the old conventions previously emitted by the instrumentation.
65
+ - `http/dup` - Emits both the old and stable HTTP and networking conventions, enabling a phased rollout of the stable semantic conventions.
66
+ - Default behavior (in the absence of either value) is to continue emitting the old HTTP and networking conventions the instrumentation previously emitted.
67
+
68
+ During the transition from old to stable conventions, Ethon instrumentation code comes in three patch versions: `dup`, `old`, and `stable`. These versions are identical except for the attributes they send. Any changes to Ethon instrumentation should consider all three patches.
69
+
70
+ For additional information on migration, please refer to our [documentation](https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/).
@@ -11,8 +11,9 @@ module OpenTelemetry
11
11
  # instrumentation
12
12
  class Instrumentation < OpenTelemetry::Instrumentation::Base
13
13
  install do |_config|
14
- require_dependencies
15
- add_patches
14
+ patch_type = determine_semconv
15
+ send(:"require_dependencies_#{patch_type}")
16
+ send(:"add_patches_#{patch_type}")
16
17
  end
17
18
 
18
19
  present do
@@ -23,13 +24,46 @@ module OpenTelemetry
23
24
 
24
25
  private
25
26
 
26
- def require_dependencies
27
- require_relative 'patches/easy'
27
+ def determine_semconv
28
+ stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', '')
29
+ values = stability_opt_in.split(',').map(&:strip)
30
+
31
+ if values.include?('http/dup')
32
+ 'dup'
33
+ elsif values.include?('http')
34
+ 'stable'
35
+ else
36
+ 'old'
37
+ end
38
+ end
39
+
40
+ def require_dependencies_dup
41
+ require_relative 'patches/dup/easy'
42
+ require_relative 'patches/multi'
43
+ end
44
+
45
+ def require_dependencies_stable
46
+ require_relative 'patches/stable/easy'
28
47
  require_relative 'patches/multi'
29
48
  end
30
49
 
31
- def add_patches
32
- ::Ethon::Easy.prepend(Patches::Easy)
50
+ def require_dependencies_old
51
+ require_relative 'patches/old/easy'
52
+ require_relative 'patches/multi'
53
+ end
54
+
55
+ def add_patches_dup
56
+ ::Ethon::Easy.prepend(Patches::Dup::Easy)
57
+ ::Ethon::Multi.prepend(Patches::Multi)
58
+ end
59
+
60
+ def add_patches_stable
61
+ ::Ethon::Easy.prepend(Patches::Stable::Easy)
62
+ ::Ethon::Multi.prepend(Patches::Multi)
63
+ end
64
+
65
+ def add_patches_old
66
+ ::Ethon::Easy.prepend(Patches::Old::Easy)
33
67
  ::Ethon::Multi.prepend(Patches::Multi)
34
68
  end
35
69
  end
@@ -0,0 +1,138 @@
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 Ethon
10
+ module Patches
11
+ # Module using old and stable HTTP semantic conventions
12
+ module Dup
13
+ # Ethon::Easy patch for instrumentation
14
+ module Easy
15
+ ACTION_NAMES_TO_HTTP_METHODS = Hash.new do |h, k|
16
+ # #to_s is required because user input could be symbol or string
17
+ h[k] = k.to_s.upcase
18
+ end
19
+ HTTP_METHODS_TO_SPAN_NAMES = Hash.new do |h, k|
20
+ h[k] = k.to_s
21
+ h[k] = 'HTTP' if k == '_OTHER'
22
+ end
23
+
24
+ # Constant for the HTTP status range
25
+ HTTP_STATUS_SUCCESS_RANGE = (100..399)
26
+
27
+ def http_request(url, action_name, options = {})
28
+ @otel_method = ACTION_NAMES_TO_HTTP_METHODS[action_name]
29
+ super
30
+ end
31
+
32
+ def headers=(headers)
33
+ # Store headers to call this method again when span is ready
34
+ @otel_original_headers = headers
35
+ super
36
+ end
37
+
38
+ def perform
39
+ otel_before_request
40
+ super
41
+ end
42
+
43
+ def complete
44
+ begin
45
+ response_options = mirror.options
46
+ response_code = (response_options[:response_code] || response_options[:code]).to_i
47
+ if response_code.zero?
48
+ return_code = response_options[:return_code]
49
+ message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
50
+ @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}")
51
+ else
52
+ @otel_span.set_attribute('http.status_code', response_code)
53
+ @otel_span.set_attribute('http.response.status_code', response_code)
54
+ @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i)
55
+ end
56
+ ensure
57
+ @otel_span&.finish
58
+ @otel_span = nil
59
+ end
60
+ super
61
+ end
62
+
63
+ def reset
64
+ super
65
+ ensure
66
+ @otel_span = nil
67
+ @otel_method = nil
68
+ @otel_original_headers = nil
69
+ end
70
+
71
+ def otel_before_request
72
+ method = '_OTHER' # Could be GET or not HTTP at all
73
+ method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
74
+
75
+ @otel_span = tracer.start_span(
76
+ HTTP_METHODS_TO_SPAN_NAMES[method],
77
+ attributes: span_creation_attributes(method),
78
+ kind: :client
79
+ )
80
+
81
+ @otel_original_headers ||= {}
82
+ OpenTelemetry::Trace.with_span(@otel_span) do
83
+ OpenTelemetry.propagation.inject(@otel_original_headers)
84
+ end
85
+ self.headers = @otel_original_headers
86
+ end
87
+
88
+ def otel_span_started?
89
+ instance_variable_defined?(:@otel_span) && !@otel_span.nil?
90
+ end
91
+
92
+ private
93
+
94
+ def span_creation_attributes(method)
95
+ http_method = (method == '_OTHER' ? 'N/A' : method)
96
+ instrumentation_attrs = {
97
+ 'http.method' => http_method,
98
+ 'http.request.method' => method
99
+ }
100
+
101
+ uri = _otel_cleanse_uri(url)
102
+ if uri
103
+ instrumentation_attrs['http.url'] = uri.to_s
104
+ instrumentation_attrs['url.full'] = uri.to_s
105
+ instrumentation_attrs['net.peer.name'] = uri.host if uri.host
106
+ instrumentation_attrs['server.address'] = uri.host if uri.host
107
+ end
108
+
109
+ config = Ethon::Instrumentation.instance.config
110
+ instrumentation_attrs['peer.service'] = config[:peer_service] if config[:peer_service]
111
+ instrumentation_attrs.merge!(
112
+ OpenTelemetry::Common::HTTP::ClientContext.attributes
113
+ )
114
+ end
115
+
116
+ # Returns a URL string with userinfo removed.
117
+ #
118
+ # @param [String] url The URL string to cleanse.
119
+ #
120
+ # @return [String] the cleansed URL.
121
+ def _otel_cleanse_uri(url)
122
+ cleansed_url = URI.parse(url)
123
+ cleansed_url.password = nil
124
+ cleansed_url.user = nil
125
+ cleansed_url
126
+ rescue URI::Error
127
+ nil
128
+ end
129
+
130
+ def tracer
131
+ Ethon::Instrumentation.instance.tracer
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,130 @@
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 Ethon
10
+ module Patches
11
+ # Module using old HTTP semantic conventions
12
+ module Old
13
+ # Ethon::Easy patch for instrumentation
14
+ module Easy
15
+ ACTION_NAMES_TO_HTTP_METHODS = Hash.new do |h, k|
16
+ # #to_s is required because user input could be symbol or string
17
+ h[k] = k.to_s.upcase
18
+ end
19
+ HTTP_METHODS_TO_SPAN_NAMES = Hash.new { |h, k| h[k] = "HTTP #{k}" }
20
+
21
+ # Constant for the HTTP status range
22
+ HTTP_STATUS_SUCCESS_RANGE = (100..399)
23
+
24
+ def http_request(url, action_name, options = {})
25
+ @otel_method = ACTION_NAMES_TO_HTTP_METHODS[action_name]
26
+ super
27
+ end
28
+
29
+ def headers=(headers)
30
+ # Store headers to call this method again when span is ready
31
+ @otel_original_headers = headers
32
+ super
33
+ end
34
+
35
+ def perform
36
+ otel_before_request
37
+ super
38
+ end
39
+
40
+ def complete
41
+ begin
42
+ response_options = mirror.options
43
+ response_code = (response_options[:response_code] || response_options[:code]).to_i
44
+ if response_code.zero?
45
+ return_code = response_options[:return_code]
46
+ message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
47
+ @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}")
48
+ else
49
+ @otel_span.set_attribute('http.status_code', response_code)
50
+ @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i)
51
+ end
52
+ ensure
53
+ @otel_span&.finish
54
+ @otel_span = nil
55
+ end
56
+ super
57
+ end
58
+
59
+ def reset
60
+ super
61
+ ensure
62
+ @otel_span = nil
63
+ @otel_method = nil
64
+ @otel_original_headers = nil
65
+ end
66
+
67
+ def otel_before_request
68
+ method = 'N/A' # Could be GET or not HTTP at all
69
+ method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
70
+
71
+ @otel_span = tracer.start_span(
72
+ HTTP_METHODS_TO_SPAN_NAMES[method],
73
+ attributes: span_creation_attributes(method),
74
+ kind: :client
75
+ )
76
+
77
+ @otel_original_headers ||= {}
78
+ OpenTelemetry::Trace.with_span(@otel_span) do
79
+ OpenTelemetry.propagation.inject(@otel_original_headers)
80
+ end
81
+ self.headers = @otel_original_headers
82
+ end
83
+
84
+ def otel_span_started?
85
+ instance_variable_defined?(:@otel_span) && !@otel_span.nil?
86
+ end
87
+
88
+ private
89
+
90
+ def span_creation_attributes(method)
91
+ instrumentation_attrs = {
92
+ 'http.method' => method
93
+ }
94
+
95
+ uri = _otel_cleanse_uri(url)
96
+ if uri
97
+ instrumentation_attrs['http.url'] = uri.to_s
98
+ instrumentation_attrs['net.peer.name'] = uri.host if uri.host
99
+ end
100
+
101
+ config = Ethon::Instrumentation.instance.config
102
+ instrumentation_attrs['peer.service'] = config[:peer_service] if config[:peer_service]
103
+ instrumentation_attrs.merge!(
104
+ OpenTelemetry::Common::HTTP::ClientContext.attributes
105
+ )
106
+ end
107
+
108
+ # Returns a URL string with userinfo removed.
109
+ #
110
+ # @param [String] url The URL string to cleanse.
111
+ #
112
+ # @return [String] the cleansed URL.
113
+ def _otel_cleanse_uri(url)
114
+ cleansed_url = URI.parse(url)
115
+ cleansed_url.password = nil
116
+ cleansed_url.user = nil
117
+ cleansed_url
118
+ rescue URI::Error
119
+ nil
120
+ end
121
+
122
+ def tracer
123
+ Ethon::Instrumentation.instance.tracer
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,133 @@
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 Ethon
10
+ module Patches
11
+ # Module using stable HTTP semantic conventions
12
+ module Stable
13
+ # Ethon::Easy patch for instrumentation
14
+ module Easy
15
+ ACTION_NAMES_TO_HTTP_METHODS = Hash.new do |h, k|
16
+ # #to_s is required because user input could be symbol or string
17
+ h[k] = k.to_s.upcase
18
+ end
19
+ HTTP_METHODS_TO_SPAN_NAMES = Hash.new do |h, k|
20
+ h[k] = k.to_s
21
+ h[k] = 'HTTP' if k == '_OTHER'
22
+ end
23
+
24
+ # Constant for the HTTP status range
25
+ HTTP_STATUS_SUCCESS_RANGE = (100..399)
26
+
27
+ def http_request(url, action_name, options = {})
28
+ @otel_method = ACTION_NAMES_TO_HTTP_METHODS[action_name]
29
+ super
30
+ end
31
+
32
+ def headers=(headers)
33
+ # Store headers to call this method again when span is ready
34
+ @otel_original_headers = headers
35
+ super
36
+ end
37
+
38
+ def perform
39
+ otel_before_request
40
+ super
41
+ end
42
+
43
+ def complete
44
+ begin
45
+ response_options = mirror.options
46
+ response_code = (response_options[:response_code] || response_options[:code]).to_i
47
+ if response_code.zero?
48
+ return_code = response_options[:return_code]
49
+ message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
50
+ @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}")
51
+ else
52
+ @otel_span.set_attribute('http.response.status_code', response_code)
53
+ @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i)
54
+ end
55
+ ensure
56
+ @otel_span&.finish
57
+ @otel_span = nil
58
+ end
59
+ super
60
+ end
61
+
62
+ def reset
63
+ super
64
+ ensure
65
+ @otel_span = nil
66
+ @otel_method = nil
67
+ @otel_original_headers = nil
68
+ end
69
+
70
+ def otel_before_request
71
+ method = '_OTHER' # Could be GET or not HTTP at all
72
+ method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
73
+
74
+ @otel_span = tracer.start_span(
75
+ HTTP_METHODS_TO_SPAN_NAMES[method],
76
+ attributes: span_creation_attributes(method),
77
+ kind: :client
78
+ )
79
+
80
+ @otel_original_headers ||= {}
81
+ OpenTelemetry::Trace.with_span(@otel_span) do
82
+ OpenTelemetry.propagation.inject(@otel_original_headers)
83
+ end
84
+ self.headers = @otel_original_headers
85
+ end
86
+
87
+ def otel_span_started?
88
+ instance_variable_defined?(:@otel_span) && !@otel_span.nil?
89
+ end
90
+
91
+ private
92
+
93
+ def span_creation_attributes(method)
94
+ instrumentation_attrs = {
95
+ 'http.request.method' => method
96
+ }
97
+
98
+ uri = _otel_cleanse_uri(url)
99
+ if uri
100
+ instrumentation_attrs['url.full'] = uri.to_s
101
+ instrumentation_attrs['server.address'] = uri.host if uri.host
102
+ end
103
+
104
+ config = Ethon::Instrumentation.instance.config
105
+ instrumentation_attrs['peer.service'] = config[:peer_service] if config[:peer_service]
106
+ instrumentation_attrs.merge!(
107
+ OpenTelemetry::Common::HTTP::ClientContext.attributes
108
+ )
109
+ end
110
+
111
+ # Returns a URL string with userinfo removed.
112
+ #
113
+ # @param [String] url The URL string to cleanse.
114
+ #
115
+ # @return [String] the cleansed URL.
116
+ def _otel_cleanse_uri(url)
117
+ cleansed_url = URI.parse(url)
118
+ cleansed_url.password = nil
119
+ cleansed_url.user = nil
120
+ cleansed_url
121
+ rescue URI::Error
122
+ nil
123
+ end
124
+
125
+ def tracer
126
+ Ethon::Instrumentation.instance.tracer
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -7,7 +7,7 @@
7
7
  module OpenTelemetry
8
8
  module Instrumentation
9
9
  module Ethon
10
- VERSION = '0.22.0'
10
+ VERSION = '0.23.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-ethon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.0
4
+ version: 0.23.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-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -38,132 +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: rubocop
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 1.69.1
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 1.69.1
125
- - !ruby/object:Gem::Dependency
126
- name: rubocop-performance
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: 1.23.0
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: 1.23.0
139
- - !ruby/object:Gem::Dependency
140
- name: simplecov
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: 0.17.1
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: 0.17.1
153
- - !ruby/object:Gem::Dependency
154
- name: yard
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '0.9'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '0.9'
167
41
  description: Ethon instrumentation for the OpenTelemetry framework
168
42
  email:
169
43
  - cncf-opentelemetry-contributors@lists.cncf.io
@@ -179,17 +53,19 @@ files:
179
53
  - lib/opentelemetry/instrumentation.rb
180
54
  - lib/opentelemetry/instrumentation/ethon.rb
181
55
  - lib/opentelemetry/instrumentation/ethon/instrumentation.rb
182
- - lib/opentelemetry/instrumentation/ethon/patches/easy.rb
56
+ - lib/opentelemetry/instrumentation/ethon/patches/dup/easy.rb
183
57
  - lib/opentelemetry/instrumentation/ethon/patches/multi.rb
58
+ - lib/opentelemetry/instrumentation/ethon/patches/old/easy.rb
59
+ - lib/opentelemetry/instrumentation/ethon/patches/stable/easy.rb
184
60
  - lib/opentelemetry/instrumentation/ethon/version.rb
185
61
  homepage: https://github.com/open-telemetry/opentelemetry-ruby-contrib
186
62
  licenses:
187
63
  - Apache-2.0
188
64
  metadata:
189
- changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-ethon/0.22.0/file/CHANGELOG.md
65
+ changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-ethon/0.23.0/file/CHANGELOG.md
190
66
  source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/ethon
191
67
  bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues
192
- documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-ethon/0.22.0
68
+ documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-ethon/0.23.0
193
69
  post_install_message:
194
70
  rdoc_options: []
195
71
  require_paths:
@@ -1,127 +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 Ethon
10
- module Patches
11
- # Ethon::Easy patch for instrumentation
12
- module Easy
13
- ACTION_NAMES_TO_HTTP_METHODS = Hash.new do |h, k|
14
- # #to_s is required because user input could be symbol or string
15
- h[k] = k.to_s.upcase
16
- end
17
- HTTP_METHODS_TO_SPAN_NAMES = Hash.new { |h, k| h[k] = "HTTP #{k}" }
18
-
19
- # Constant for the HTTP status range
20
- HTTP_STATUS_SUCCESS_RANGE = (100..399)
21
-
22
- def http_request(url, action_name, options = {})
23
- @otel_method = ACTION_NAMES_TO_HTTP_METHODS[action_name]
24
- super
25
- end
26
-
27
- def headers=(headers)
28
- # Store headers to call this method again when span is ready
29
- @otel_original_headers = headers
30
- super
31
- end
32
-
33
- def perform
34
- otel_before_request
35
- super
36
- end
37
-
38
- def complete
39
- begin
40
- response_options = mirror.options
41
- response_code = (response_options[:response_code] || response_options[:code]).to_i
42
- if response_code.zero?
43
- return_code = response_options[:return_code]
44
- message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
45
- @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}")
46
- else
47
- @otel_span.set_attribute('http.status_code', response_code)
48
- @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i)
49
- end
50
- ensure
51
- @otel_span&.finish
52
- @otel_span = nil
53
- end
54
- super
55
- end
56
-
57
- def reset
58
- super
59
- ensure
60
- @otel_span = nil
61
- @otel_method = nil
62
- @otel_original_headers = nil
63
- end
64
-
65
- def otel_before_request
66
- method = 'N/A' # Could be GET or not HTTP at all
67
- method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
68
-
69
- @otel_span = tracer.start_span(
70
- HTTP_METHODS_TO_SPAN_NAMES[method],
71
- attributes: span_creation_attributes(method),
72
- kind: :client
73
- )
74
-
75
- @otel_original_headers ||= {}
76
- OpenTelemetry::Trace.with_span(@otel_span) do
77
- OpenTelemetry.propagation.inject(@otel_original_headers)
78
- end
79
- self.headers = @otel_original_headers
80
- end
81
-
82
- def otel_span_started?
83
- instance_variable_defined?(:@otel_span) && !@otel_span.nil?
84
- end
85
-
86
- private
87
-
88
- def span_creation_attributes(method)
89
- instrumentation_attrs = {
90
- 'http.method' => method
91
- }
92
-
93
- uri = _otel_cleanse_uri(url)
94
- if uri
95
- instrumentation_attrs['http.url'] = uri.to_s
96
- instrumentation_attrs['net.peer.name'] = uri.host if uri.host
97
- end
98
-
99
- config = Ethon::Instrumentation.instance.config
100
- instrumentation_attrs['peer.service'] = config[:peer_service] if config[:peer_service]
101
- instrumentation_attrs.merge!(
102
- OpenTelemetry::Common::HTTP::ClientContext.attributes
103
- )
104
- end
105
-
106
- # Returns a URL string with userinfo removed.
107
- #
108
- # @param [String] url The URL string to cleanse.
109
- #
110
- # @return [String] the cleansed URL.
111
- def _otel_cleanse_uri(url)
112
- cleansed_url = URI.parse(url)
113
- cleansed_url.password = nil
114
- cleansed_url.user = nil
115
- cleansed_url
116
- rescue URI::Error
117
- nil
118
- end
119
-
120
- def tracer
121
- Ethon::Instrumentation.instance.tracer
122
- end
123
- end
124
- end
125
- end
126
- end
127
- end