opentelemetry-instrumentation-ethon 0.22.0 → 0.23.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: 5da94e8bf071f770f1bed046b0a7766e14380162d72a6d5e5ed2d32d386aaea2
4
- data.tar.gz: 974c11a490e18fbe95826cd9cb2929d253c7d217baf25d9bc627a9444b51c5f6
3
+ metadata.gz: c84a22f816b0575721fa9e501efc78f58af6e15e968ed83faf8c0cf546833783
4
+ data.tar.gz: 8a19d873db4b6ea144cbbc187e319476a8aaddfc58be35ae4507df999cfe775a
5
5
  SHA512:
6
- metadata.gz: 0e31a35b06cbb27f95f0a6f07a7198244b6513e640f009ec66a190cae0a4413e2f38219c187cd9ee99675d26a4b329f10f7e91212f90c08d6db3e3b03ac6fc99
7
- data.tar.gz: b3d37196e2a1774e90f50050df1be49966fff0b43cbd2db2513ea0a955c122793a591dc08151fea1e6a95f8f662afe57677a3532c71aa0354376ac8390b57d45
6
+ metadata.gz: e69933909862ca50e1c0ecc8845d4ae9625e3f03c6a67487a43c82447144478a30dbf36dc0f0f5a678c6868016c7f54188ce07ebae3d9b0c0309fc969c20129b
7
+ data.tar.gz: 36cd30785a9ff5f6e422b35ae6b1213c5d85d3f84087bfe05cf1cb8826e755b3fb95a16f3ba7aff70e060c434c1fb115c29b75472ff3174ddd4a8bb59fe13b59
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Release History: opentelemetry-instrumentation-ethon
2
2
 
3
+ ### v0.23.1 / 2025-09-02
4
+
5
+ * FIXED: Improve Ethon exception handling
6
+
7
+ ### v0.23.0 / 2025-08-13
8
+
9
+ * ADDED: Add Ethon `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable [#1561](https://github.com/open-telemetry/opentelemetry-ruby-contrib/pull/1561)
10
+
3
11
  ### v0.22.0 / 2025-01-16
4
12
 
5
13
  * BREAKING CHANGE: Set minimum supported version to Ruby 3.1
@@ -40,23 +48,23 @@
40
48
 
41
49
  ### v0.21.1 / 2023-06-05
42
50
 
43
- * FIXED: Base config options
51
+ * FIXED: Base config options
44
52
 
45
53
  ### v0.21.0 / 2023-04-17
46
54
 
47
- * BREAKING CHANGE: Drop support for EoL Ruby 2.7
55
+ * BREAKING CHANGE: Drop support for EoL Ruby 2.7
48
56
 
49
- * ADDED: Drop support for EoL Ruby 2.7
57
+ * ADDED: Drop support for EoL Ruby 2.7
50
58
 
51
59
  ### v0.20.1 / 2023-01-14
52
60
 
53
- * DOCS: Fix gem homepage
54
- * DOCS: More gem documentation fixes
61
+ * DOCS: Fix gem homepage
62
+ * DOCS: More gem documentation fixes
55
63
 
56
64
  ### v0.20.0 / 2022-06-09
57
65
 
58
66
  * Upgrading Base dependency version
59
- * FIXED: Broken test file requirements
67
+ * FIXED: Broken test file requirements
60
68
 
61
69
  ### v0.19.5 / 2022-05-05
62
70
 
@@ -64,7 +72,7 @@
64
72
 
65
73
  ### v0.19.4 / 2022-02-02
66
74
 
67
- * FIXED: Excessive hash creation on context attr merging
75
+ * FIXED: Excessive hash creation on context attr merging
68
76
 
69
77
  ### v0.19.3 / 2021-12-02
70
78
 
@@ -76,13 +84,13 @@
76
84
 
77
85
  ### v0.19.1 / 2021-08-12
78
86
 
79
- * DOCS: Update docs to rely more on environment variable configuration
87
+ * DOCS: Update docs to rely more on environment variable configuration
80
88
 
81
89
  ### v0.19.0 / 2021-06-23
82
90
 
83
- * BREAKING CHANGE: Total order constraint on span.status=
91
+ * BREAKING CHANGE: Total order constraint on span.status=
84
92
 
85
- * FIXED: Total order constraint on span.status=
93
+ * FIXED: Total order constraint on span.status=
86
94
 
87
95
  ### v0.18.0 / 2021-05-21
88
96
 
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,143 @@
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
+ rescue StandardError => e
42
+ # If an exception occurs before we can call `complete`, we should add and error status and close the span
43
+ @otel_span&.status = OpenTelemetry::Trace::Status.error("Request threw an exception: #{e.message}")
44
+ @otel_span&.finish
45
+ @otel_span = nil
46
+ end
47
+
48
+ def complete
49
+ begin
50
+ response_options = mirror.options
51
+ response_code = (response_options[:response_code] || response_options[:code]).to_i
52
+ if response_code.zero?
53
+ return_code = response_options[:return_code]
54
+ message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
55
+ @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}")
56
+ else
57
+ @otel_span.set_attribute('http.status_code', response_code)
58
+ @otel_span.set_attribute('http.response.status_code', response_code)
59
+ @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i)
60
+ end
61
+ ensure
62
+ @otel_span&.finish
63
+ @otel_span = nil
64
+ end
65
+ super
66
+ end
67
+
68
+ def reset
69
+ super
70
+ ensure
71
+ @otel_span = nil
72
+ @otel_method = nil
73
+ @otel_original_headers = nil
74
+ end
75
+
76
+ def otel_before_request
77
+ method = '_OTHER' # Could be GET or not HTTP at all
78
+ method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
79
+
80
+ @otel_span = tracer.start_span(
81
+ HTTP_METHODS_TO_SPAN_NAMES[method],
82
+ attributes: span_creation_attributes(method),
83
+ kind: :client
84
+ )
85
+
86
+ @otel_original_headers ||= {}
87
+ OpenTelemetry::Trace.with_span(@otel_span) do
88
+ OpenTelemetry.propagation.inject(@otel_original_headers)
89
+ end
90
+ self.headers = @otel_original_headers
91
+ end
92
+
93
+ def otel_span_started?
94
+ instance_variable_defined?(:@otel_span) && !@otel_span.nil?
95
+ end
96
+
97
+ private
98
+
99
+ def span_creation_attributes(method)
100
+ http_method = (method == '_OTHER' ? 'N/A' : method)
101
+ instrumentation_attrs = {
102
+ 'http.method' => http_method,
103
+ 'http.request.method' => method
104
+ }
105
+
106
+ uri = _otel_cleanse_uri(url)
107
+ if uri
108
+ instrumentation_attrs['http.url'] = uri.to_s
109
+ instrumentation_attrs['url.full'] = uri.to_s
110
+ instrumentation_attrs['net.peer.name'] = uri.host if uri.host
111
+ instrumentation_attrs['server.address'] = uri.host if uri.host
112
+ end
113
+
114
+ config = Ethon::Instrumentation.instance.config
115
+ instrumentation_attrs['peer.service'] = config[:peer_service] if config[:peer_service]
116
+ instrumentation_attrs.merge!(
117
+ OpenTelemetry::Common::HTTP::ClientContext.attributes
118
+ )
119
+ end
120
+
121
+ # Returns a URL string with userinfo removed.
122
+ #
123
+ # @param [String] url The URL string to cleanse.
124
+ #
125
+ # @return [String] the cleansed URL.
126
+ def _otel_cleanse_uri(url)
127
+ cleansed_url = URI.parse(url)
128
+ cleansed_url.password = nil
129
+ cleansed_url.user = nil
130
+ cleansed_url
131
+ rescue URI::Error
132
+ nil
133
+ end
134
+
135
+ def tracer
136
+ Ethon::Instrumentation.instance.tracer
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,135 @@
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
+ rescue StandardError => e
39
+ # If an exception occurs before we can call `complete`, we should add and error status and close the span
40
+ @otel_span&.status = OpenTelemetry::Trace::Status.error("Request threw an exception: #{e.message}")
41
+ @otel_span&.finish
42
+ @otel_span = nil
43
+ end
44
+
45
+ def complete
46
+ begin
47
+ response_options = mirror.options
48
+ response_code = (response_options[:response_code] || response_options[:code]).to_i
49
+ if response_code.zero?
50
+ return_code = response_options[:return_code]
51
+ message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
52
+ @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}")
53
+ else
54
+ @otel_span.set_attribute('http.status_code', response_code)
55
+ @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i)
56
+ end
57
+ ensure
58
+ @otel_span&.finish
59
+ @otel_span = nil
60
+ end
61
+ super
62
+ end
63
+
64
+ def reset
65
+ super
66
+ ensure
67
+ @otel_span = nil
68
+ @otel_method = nil
69
+ @otel_original_headers = nil
70
+ end
71
+
72
+ def otel_before_request
73
+ method = 'N/A' # Could be GET or not HTTP at all
74
+ method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
75
+
76
+ @otel_span = tracer.start_span(
77
+ HTTP_METHODS_TO_SPAN_NAMES[method],
78
+ attributes: span_creation_attributes(method),
79
+ kind: :client
80
+ )
81
+
82
+ @otel_original_headers ||= {}
83
+ OpenTelemetry::Trace.with_span(@otel_span) do
84
+ OpenTelemetry.propagation.inject(@otel_original_headers)
85
+ end
86
+ self.headers = @otel_original_headers
87
+ end
88
+
89
+ def otel_span_started?
90
+ instance_variable_defined?(:@otel_span) && !@otel_span.nil?
91
+ end
92
+
93
+ private
94
+
95
+ def span_creation_attributes(method)
96
+ instrumentation_attrs = {
97
+ 'http.method' => method
98
+ }
99
+
100
+ uri = _otel_cleanse_uri(url)
101
+ if uri
102
+ instrumentation_attrs['http.url'] = uri.to_s
103
+ instrumentation_attrs['net.peer.name'] = uri.host if uri.host
104
+ end
105
+
106
+ config = Ethon::Instrumentation.instance.config
107
+ instrumentation_attrs['peer.service'] = config[:peer_service] if config[:peer_service]
108
+ instrumentation_attrs.merge!(
109
+ OpenTelemetry::Common::HTTP::ClientContext.attributes
110
+ )
111
+ end
112
+
113
+ # Returns a URL string with userinfo removed.
114
+ #
115
+ # @param [String] url The URL string to cleanse.
116
+ #
117
+ # @return [String] the cleansed URL.
118
+ def _otel_cleanse_uri(url)
119
+ cleansed_url = URI.parse(url)
120
+ cleansed_url.password = nil
121
+ cleansed_url.user = nil
122
+ cleansed_url
123
+ rescue URI::Error
124
+ nil
125
+ end
126
+
127
+ def tracer
128
+ Ethon::Instrumentation.instance.tracer
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+ 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 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
+ rescue StandardError => e
42
+ # If an exception occurs before we can call `complete`, we should add and error status and close the span
43
+ @otel_span&.status = OpenTelemetry::Trace::Status.error("Request threw an exception: #{e.message}")
44
+ @otel_span&.finish
45
+ @otel_span = nil
46
+ end
47
+
48
+ def complete
49
+ begin
50
+ response_options = mirror.options
51
+ response_code = (response_options[:response_code] || response_options[:code]).to_i
52
+ if response_code.zero?
53
+ return_code = response_options[:return_code]
54
+ message = return_code ? ::Ethon::Curl.easy_strerror(return_code) : 'unknown reason'
55
+ @otel_span.status = OpenTelemetry::Trace::Status.error("Request has failed: #{message}")
56
+ else
57
+ @otel_span.set_attribute('http.response.status_code', response_code)
58
+ @otel_span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response_code.to_i)
59
+ end
60
+ ensure
61
+ @otel_span&.finish
62
+ @otel_span = nil
63
+ end
64
+ super
65
+ end
66
+
67
+ def reset
68
+ super
69
+ ensure
70
+ @otel_span = nil
71
+ @otel_method = nil
72
+ @otel_original_headers = nil
73
+ end
74
+
75
+ def otel_before_request
76
+ method = '_OTHER' # Could be GET or not HTTP at all
77
+ method = @otel_method if instance_variable_defined?(:@otel_method) && !@otel_method.nil?
78
+
79
+ @otel_span = tracer.start_span(
80
+ HTTP_METHODS_TO_SPAN_NAMES[method],
81
+ attributes: span_creation_attributes(method),
82
+ kind: :client
83
+ )
84
+
85
+ @otel_original_headers ||= {}
86
+ OpenTelemetry::Trace.with_span(@otel_span) do
87
+ OpenTelemetry.propagation.inject(@otel_original_headers)
88
+ end
89
+ self.headers = @otel_original_headers
90
+ end
91
+
92
+ def otel_span_started?
93
+ instance_variable_defined?(:@otel_span) && !@otel_span.nil?
94
+ end
95
+
96
+ private
97
+
98
+ def span_creation_attributes(method)
99
+ instrumentation_attrs = {
100
+ 'http.request.method' => method
101
+ }
102
+
103
+ uri = _otel_cleanse_uri(url)
104
+ if uri
105
+ instrumentation_attrs['url.full'] = uri.to_s
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
@@ -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.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-ethon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.0
4
+ version: 0.23.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-09-03 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.1/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.1
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