opentelemetry-instrumentation-excon 0.26.0 → 0.26.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: 55f08b360e4258d9bd2997473e1dbb1338c5477d5c799e63c7502ef1a56579e8
4
- data.tar.gz: d78813a8340f4c2fd778e67f36d0bfd13583a1f4694ffc1f77b4462da59a0ffd
3
+ metadata.gz: a921d5ad6cdca93a94fd432db5cf0d8ef32438912de3ed1d598dc32421b59913
4
+ data.tar.gz: dd27126b88bf80c23e3edaf7387dceb85cc5f8127bedc57158572133d551187e
5
5
  SHA512:
6
- metadata.gz: e0681af77b94c0867317c7cac240265eb0791b6985bdbf3b77f728db1ada771c4049f33a15744ea091e44ead5108a5fe823de766431bf23ac0b6283c50c7ed08
7
- data.tar.gz: 5f4898589653da3c992839620d3fcf2c407616ff83726ae4e8ae1cb921032aeb13b9357c44846b77c01bf8ccb9210147fc8dcb584438539f3a30e5514e3ef107
6
+ metadata.gz: c138a2b32ca6a3d6c99510a6bdd16407f2451e2e870dc8cf14403628c2268ddb85c3f61d20d3331d868cc76a02c11eaa5b89150714751fc4c76941700b9fc61a
7
+ data.tar.gz: ec4d44aea8941398abf1eae8247487c3f1973e6dee70e32c4fa5e3e577e15f9d7e5d1c7e69135f7adece7733db3a8a1ce9bd5546c5c5e19848f6ed6fee8b55ff
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Release History: opentelemetry-instrumentation-excon
2
2
 
3
+ ### v0.26.1 / 2025-11-25
4
+
5
+ * FIXED: Update support for unknown HTTP methods to match semantic conventions
6
+
3
7
  ### v0.26.0 / 2025-10-22
4
8
 
5
9
  * BREAKING CHANGE: Min Ruby Version 3.2
@@ -0,0 +1,86 @@
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 Excon
10
+ # Utility module for HTTP-related helper methods
11
+ # @api private
12
+ module HttpHelper
13
+ # Lightweight struct to hold span creation attributes
14
+ SpanCreationAttributes = Struct.new(:span_name, :normalized_method, :original_method, keyword_init: true)
15
+
16
+ # Pre-computed mapping to avoid string allocations during normalization
17
+ METHOD_CACHE = {
18
+ 'CONNECT' => 'CONNECT',
19
+ 'DELETE' => 'DELETE',
20
+ 'GET' => 'GET',
21
+ 'HEAD' => 'HEAD',
22
+ 'OPTIONS' => 'OPTIONS',
23
+ 'PATCH' => 'PATCH',
24
+ 'POST' => 'POST',
25
+ 'PUT' => 'PUT',
26
+ 'TRACE' => 'TRACE',
27
+ 'connect' => 'CONNECT',
28
+ 'delete' => 'DELETE',
29
+ 'get' => 'GET',
30
+ 'head' => 'HEAD',
31
+ 'options' => 'OPTIONS',
32
+ 'patch' => 'PATCH',
33
+ 'post' => 'POST',
34
+ 'put' => 'PUT',
35
+ 'trace' => 'TRACE',
36
+ :connect => 'CONNECT',
37
+ :delete => 'DELETE',
38
+ :get => 'GET',
39
+ :head => 'HEAD',
40
+ :options => 'OPTIONS',
41
+ :patch => 'PATCH',
42
+ :post => 'POST',
43
+ :put => 'PUT',
44
+ :trace => 'TRACE'
45
+ }.freeze
46
+
47
+ # Pre-computed span names for old semantic conventions to avoid allocations
48
+ OLD_SPAN_NAMES = {
49
+ 'CONNECT' => 'HTTP CONNECT',
50
+ 'DELETE' => 'HTTP DELETE',
51
+ 'GET' => 'HTTP GET',
52
+ 'HEAD' => 'HTTP HEAD',
53
+ 'OPTIONS' => 'HTTP OPTIONS',
54
+ 'PATCH' => 'HTTP PATCH',
55
+ 'POST' => 'HTTP POST',
56
+ 'PUT' => 'HTTP PUT',
57
+ 'TRACE' => 'HTTP TRACE'
58
+ }.freeze
59
+
60
+ private_constant :METHOD_CACHE, :OLD_SPAN_NAMES
61
+
62
+ # Prepares all span data for the specified semantic convention in a single call
63
+ # @param method [String, Symbol] The HTTP method
64
+ # @param semconv [Symbol] The semantic convention to use (:stable or :old)
65
+ # @return [SpanCreationAttributes] struct containing span_name, normalized_method, and original_method
66
+ def self.span_attrs_for(method, semconv: :stable)
67
+ normalized = METHOD_CACHE[method]
68
+ if normalized
69
+ span_name = semconv == :old ? OLD_SPAN_NAMES[normalized] : normalized
70
+ SpanCreationAttributes.new(
71
+ span_name: span_name,
72
+ normalized_method: normalized,
73
+ original_method: nil
74
+ )
75
+ else
76
+ SpanCreationAttributes.new(
77
+ span_name: 'HTTP',
78
+ normalized_method: '_OTHER',
79
+ original_method: method.to_s
80
+ )
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -11,45 +11,36 @@ module OpenTelemetry
11
11
  module Dup
12
12
  # Excon middleware for instrumentation
13
13
  class TracerMiddleware < ::Excon::Middleware::Base
14
- HTTP_METHODS_TO_UPPERCASE = %w[connect delete get head options patch post put trace].each_with_object({}) do |method, hash|
15
- uppercase_method = method.upcase
16
- hash[method] = uppercase_method
17
- hash[method.to_sym] = uppercase_method
18
- hash[uppercase_method] = uppercase_method
19
- end.freeze
20
-
21
- HTTP_METHODS_TO_SPAN_NAMES = HTTP_METHODS_TO_UPPERCASE.values.each_with_object({}) do |uppercase_method, hash|
22
- hash[uppercase_method] ||= uppercase_method
23
- end.freeze
24
-
25
14
  # Constant for the HTTP status range
26
15
  HTTP_STATUS_SUCCESS_RANGE = (100..399)
27
16
 
28
17
  def request_call(datum)
29
18
  return @stack.request_call(datum) if untraced?(datum)
30
19
 
31
- http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]]
20
+ span_data = HttpHelper.span_attrs_for(datum[:method])
21
+
32
22
  cleansed_url = OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum))
33
23
  attributes = {
34
24
  OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => datum[:host],
35
- OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method,
25
+ OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => span_data.normalized_method,
36
26
  OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => datum[:scheme],
37
27
  OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => datum[:path],
38
28
  OpenTelemetry::SemanticConventions::Trace::HTTP_URL => cleansed_url,
39
29
  OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => datum[:hostname],
40
30
  OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => datum[:port],
41
- 'http.request.method' => http_method,
31
+ 'http.request.method' => span_data.normalized_method,
42
32
  'url.scheme' => datum[:scheme],
43
33
  'url.path' => datum[:path],
44
34
  'url.full' => cleansed_url,
45
35
  'server.address' => datum[:hostname],
46
36
  'server.port' => datum[:port]
47
37
  }
38
+ attributes['http.request.method_original'] = span_data.original_method if span_data.original_method
48
39
  attributes['url.query'] = datum[:query] if datum[:query]
49
40
  peer_service = Excon::Instrumentation.instance.config[:peer_service]
50
41
  attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service
51
42
  attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
52
- span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client)
43
+ span = tracer.start_span(span_data.span_name, attributes: attributes, kind: :client)
53
44
  ctx = OpenTelemetry::Trace.context_with_span(span)
54
45
  datum[:otel_span] = span
55
46
  datum[:otel_token] = OpenTelemetry::Context.attach(ctx)
@@ -11,27 +11,17 @@ module OpenTelemetry
11
11
  module Old
12
12
  # Excon middleware for instrumentation
13
13
  class TracerMiddleware < ::Excon::Middleware::Base
14
- HTTP_METHODS_TO_UPPERCASE = %w[connect delete get head options patch post put trace].each_with_object({}) do |method, hash|
15
- uppercase_method = method.upcase
16
- hash[method] = uppercase_method
17
- hash[method.to_sym] = uppercase_method
18
- hash[uppercase_method] = uppercase_method
19
- end.freeze
20
-
21
- HTTP_METHODS_TO_SPAN_NAMES = HTTP_METHODS_TO_UPPERCASE.values.each_with_object({}) do |uppercase_method, hash|
22
- hash[uppercase_method] ||= "HTTP #{uppercase_method}"
23
- end.freeze
24
-
25
14
  # Constant for the HTTP status range
26
15
  HTTP_STATUS_SUCCESS_RANGE = (100..399)
27
16
 
28
17
  def request_call(datum)
29
18
  return @stack.request_call(datum) if untraced?(datum)
30
19
 
31
- http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]]
20
+ span_data = HttpHelper.span_attrs_for(datum[:method], semconv: :old)
21
+
32
22
  attributes = {
33
23
  OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => datum[:host],
34
- OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method,
24
+ OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => span_data.normalized_method,
35
25
  OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => datum[:scheme],
36
26
  OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => datum[:path],
37
27
  OpenTelemetry::SemanticConventions::Trace::HTTP_URL => OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum)),
@@ -41,7 +31,7 @@ module OpenTelemetry
41
31
  peer_service = Excon::Instrumentation.instance.config[:peer_service]
42
32
  attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service
43
33
  attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
44
- span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client)
34
+ span = tracer.start_span(span_data.span_name, attributes: attributes, kind: :client)
45
35
  ctx = OpenTelemetry::Trace.context_with_span(span)
46
36
  datum[:otel_span] = span
47
37
  datum[:otel_token] = OpenTelemetry::Context.attach(ctx)
@@ -11,37 +11,28 @@ module OpenTelemetry
11
11
  module Stable
12
12
  # Excon middleware for instrumentation
13
13
  class TracerMiddleware < ::Excon::Middleware::Base
14
- HTTP_METHODS_TO_UPPERCASE = %w[connect delete get head options patch post put trace].each_with_object({}) do |method, hash|
15
- uppercase_method = method.upcase
16
- hash[method] = uppercase_method
17
- hash[method.to_sym] = uppercase_method
18
- hash[uppercase_method] = uppercase_method
19
- end.freeze
20
-
21
- HTTP_METHODS_TO_SPAN_NAMES = HTTP_METHODS_TO_UPPERCASE.values.each_with_object({}) do |uppercase_method, hash|
22
- hash[uppercase_method] ||= uppercase_method
23
- end.freeze
24
-
25
14
  # Constant for the HTTP status range
26
15
  HTTP_STATUS_SUCCESS_RANGE = (100..399)
27
16
 
28
17
  def request_call(datum)
29
18
  return @stack.request_call(datum) if untraced?(datum)
30
19
 
31
- http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]]
20
+ span_data = HttpHelper.span_attrs_for(datum[:method])
21
+
32
22
  attributes = {
33
- 'http.request.method' => http_method,
23
+ 'http.request.method' => span_data.normalized_method,
34
24
  'url.scheme' => datum[:scheme],
35
25
  'url.path' => datum[:path],
36
26
  'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum)),
37
27
  'server.address' => datum[:hostname],
38
28
  'server.port' => datum[:port]
39
29
  }
30
+ attributes['http.request.method_original'] = span_data.original_method if span_data.original_method
40
31
  attributes['url.query'] = datum[:query] if datum[:query]
41
32
  peer_service = Excon::Instrumentation.instance.config[:peer_service]
42
33
  attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service
43
34
  attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
44
- span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client)
35
+ span = tracer.start_span(span_data.span_name, attributes: attributes, kind: :client)
45
36
  ctx = OpenTelemetry::Trace.context_with_span(span)
46
37
  datum[:otel_span] = span
47
38
  datum[:otel_token] = OpenTelemetry::Context.attach(ctx)
@@ -7,7 +7,7 @@
7
7
  module OpenTelemetry
8
8
  module Instrumentation
9
9
  module Excon
10
- VERSION = '0.26.0'
10
+ VERSION = '0.26.1'
11
11
  end
12
12
  end
13
13
  end
@@ -15,5 +15,6 @@ module OpenTelemetry
15
15
  end
16
16
  end
17
17
 
18
+ require_relative 'excon/http_helper'
18
19
  require_relative 'excon/instrumentation'
19
20
  require_relative 'excon/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opentelemetry-instrumentation-excon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.26.0
4
+ version: 0.26.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-10-22 00:00:00.000000000 Z
11
+ date: 2025-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-instrumentation-base
@@ -39,6 +39,7 @@ files:
39
39
  - lib/opentelemetry/instrumentation.rb
40
40
  - lib/opentelemetry/instrumentation/concerns/untraced_hosts.rb
41
41
  - lib/opentelemetry/instrumentation/excon.rb
42
+ - lib/opentelemetry/instrumentation/excon/http_helper.rb
42
43
  - lib/opentelemetry/instrumentation/excon/instrumentation.rb
43
44
  - lib/opentelemetry/instrumentation/excon/middlewares/dup/tracer_middleware.rb
44
45
  - lib/opentelemetry/instrumentation/excon/middlewares/old/tracer_middleware.rb
@@ -51,10 +52,10 @@ homepage: https://github.com/open-telemetry/opentelemetry-ruby-contrib
51
52
  licenses:
52
53
  - Apache-2.0
53
54
  metadata:
54
- changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.26.0/file/CHANGELOG.md
55
+ changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.26.1/file/CHANGELOG.md
55
56
  source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/excon
56
57
  bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues
57
- documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.26.0
58
+ documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.26.1
58
59
  post_install_message:
59
60
  rdoc_options: []
60
61
  require_paths: