opentelemetry-instrumentation-excon 0.23.0 → 0.24.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +17 -0
- data/lib/opentelemetry/instrumentation/excon/instrumentation.rb +50 -10
- data/lib/opentelemetry/instrumentation/excon/middlewares/dup/tracer_middleware.rb +120 -0
- data/lib/opentelemetry/instrumentation/excon/middlewares/old/tracer_middleware.rb +111 -0
- data/lib/opentelemetry/instrumentation/excon/middlewares/stable/tracer_middleware.rb +111 -0
- data/lib/opentelemetry/instrumentation/excon/patches/dup/socket.rb +65 -0
- data/lib/opentelemetry/instrumentation/excon/patches/old/socket.rb +60 -0
- data/lib/opentelemetry/instrumentation/excon/patches/stable/socket.rb +60 -0
- data/lib/opentelemetry/instrumentation/excon/version.rb +1 -1
- metadata +10 -146
- data/lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb +0 -109
- data/lib/opentelemetry/instrumentation/excon/patches/socket.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 665fc138f916ed28ac04ad618f3763d486100fdfb728eb6f36afe5be44b91ea3
|
4
|
+
data.tar.gz: ab39b09837a43e659d25209960b649bd9070905f751abddd5d494e64a69b831b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9aeb16c010bfee7044705d6d0a85583adfa91cb27cba4ad3cc79ba8773bd9d9edfefd8646e63d5d0724ef1c8b2051962fc606155e7f5358539cd222fdf261ba2
|
7
|
+
data.tar.gz: c497f7b505130661372b15f1c594e2084ba9a3696fba0f9f11ac132a3a9f84e8f30ce28079af653337bcdb4f18539c996f7afa9aed6a5a00822d3ecb7387fd6b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Release History: opentelemetry-instrumentation-excon
|
2
2
|
|
3
|
+
### v0.24.0 / 2025-08-12
|
4
|
+
|
5
|
+
* ADDED: Add Excon `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable [#1569](https://github.com/open-telemetry/opentelemetry-ruby-contrib/pull/1569)
|
6
|
+
|
3
7
|
### v0.23.0 / 2025-01-16
|
4
8
|
|
5
9
|
* BREAKING CHANGE: Set minimum supported version to Ruby 3.1
|
data/README.md
CHANGED
@@ -48,3 +48,20 @@ The `opentelemetry-instrumentation-all` gem is distributed under the Apache 2.0
|
|
48
48
|
[community-meetings]: https://github.com/open-telemetry/community#community-meetings
|
49
49
|
[slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY
|
50
50
|
[discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions
|
51
|
+
|
52
|
+
|
53
|
+
## HTTP semantic convention stability
|
54
|
+
|
55
|
+
In the OpenTelemetry ecosystem, HTTP semantic conventions have now reached a stable state. However, the initial Excon instrumentation was introduced before this stability was achieved, which resulted in HTTP attributes being based on an older version of the semantic conventions.
|
56
|
+
|
57
|
+
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.
|
58
|
+
|
59
|
+
When setting the value for `OTEL_SEMCONV_STABILITY_OPT_IN`, you can specify which conventions you wish to adopt:
|
60
|
+
|
61
|
+
- `http` - Emits the stable HTTP and networking conventions and ceases emitting the old conventions previously emitted by the instrumentation.
|
62
|
+
- `http/dup` - Emits both the old and stable HTTP and networking conventions, enabling a phased rollout of the stable semantic conventions.
|
63
|
+
- Default behavior (in the absence of either value) is to continue emitting the old HTTP and networking conventions the instrumentation previously emitted.
|
64
|
+
|
65
|
+
During the transition from old to stable conventions, Excon instrumentation code comes in three patch versions: `dup`, `old`, and `stable`. These versions are identical except for the attributes they send. Any changes to Excon instrumentation should consider all three patches.
|
66
|
+
|
67
|
+
For additional information on migration, please refer to our [documentation](https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/).
|
@@ -15,9 +15,10 @@ module OpenTelemetry
|
|
15
15
|
include OpenTelemetry::Instrumentation::Concerns::UntracedHosts
|
16
16
|
|
17
17
|
install do |_config|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
patch_type = determine_semconv
|
19
|
+
send(:"require_dependencies_#{patch_type}")
|
20
|
+
send(:"add_middleware_#{patch_type}")
|
21
|
+
send(:"patch_#{patch_type}")
|
21
22
|
end
|
22
23
|
|
23
24
|
present do
|
@@ -28,17 +29,56 @@ module OpenTelemetry
|
|
28
29
|
|
29
30
|
private
|
30
31
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
32
|
+
def determine_semconv
|
33
|
+
stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', '')
|
34
|
+
values = stability_opt_in.split(',').map(&:strip)
|
35
|
+
|
36
|
+
if values.include?('http/dup')
|
37
|
+
'dup'
|
38
|
+
elsif values.include?('http')
|
39
|
+
'stable'
|
40
|
+
else
|
41
|
+
'old'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def require_dependencies_dup
|
46
|
+
require_relative 'middlewares/dup/tracer_middleware'
|
47
|
+
require_relative 'patches/dup/socket'
|
48
|
+
end
|
49
|
+
|
50
|
+
def require_dependencies_stable
|
51
|
+
require_relative 'middlewares/stable/tracer_middleware'
|
52
|
+
require_relative 'patches/stable/socket'
|
53
|
+
end
|
54
|
+
|
55
|
+
def require_dependencies_old
|
56
|
+
require_relative 'middlewares/old/tracer_middleware'
|
57
|
+
require_relative 'patches/old/socket'
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_middleware_dup
|
61
|
+
::Excon.defaults[:middlewares] = Middlewares::Dup::TracerMiddleware.around_default_stack
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_middleware_stable
|
65
|
+
::Excon.defaults[:middlewares] = Middlewares::Stable::TracerMiddleware.around_default_stack
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_middleware_old
|
69
|
+
::Excon.defaults[:middlewares] = Middlewares::Old::TracerMiddleware.around_default_stack
|
70
|
+
end
|
71
|
+
|
72
|
+
def patch_dup
|
73
|
+
::Excon::Socket.prepend(Patches::Dup::Socket)
|
34
74
|
end
|
35
75
|
|
36
|
-
def
|
37
|
-
::Excon.
|
76
|
+
def patch_stable
|
77
|
+
::Excon::Socket.prepend(Patches::Stable::Socket)
|
38
78
|
end
|
39
79
|
|
40
|
-
def
|
41
|
-
::Excon::Socket.prepend(Patches::Socket)
|
80
|
+
def patch_old
|
81
|
+
::Excon::Socket.prepend(Patches::Old::Socket)
|
42
82
|
end
|
43
83
|
end
|
44
84
|
end
|
@@ -0,0 +1,120 @@
|
|
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
|
+
module Middlewares
|
11
|
+
module Dup
|
12
|
+
# Excon middleware for instrumentation
|
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
|
+
# Constant for the HTTP status range
|
26
|
+
HTTP_STATUS_SUCCESS_RANGE = (100..399)
|
27
|
+
|
28
|
+
def request_call(datum)
|
29
|
+
return @stack.request_call(datum) if untraced?(datum)
|
30
|
+
|
31
|
+
http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]]
|
32
|
+
cleansed_url = OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum))
|
33
|
+
attributes = {
|
34
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => datum[:host],
|
35
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method,
|
36
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => datum[:scheme],
|
37
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => datum[:path],
|
38
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_URL => cleansed_url,
|
39
|
+
OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => datum[:hostname],
|
40
|
+
OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => datum[:port],
|
41
|
+
'http.request.method' => http_method,
|
42
|
+
'url.scheme' => datum[:scheme],
|
43
|
+
'url.path' => datum[:path],
|
44
|
+
'url.full' => cleansed_url,
|
45
|
+
'server.address' => datum[:hostname],
|
46
|
+
'server.port' => datum[:port]
|
47
|
+
}
|
48
|
+
attributes['url.query'] = datum[:query] if datum[:query]
|
49
|
+
peer_service = Excon::Instrumentation.instance.config[:peer_service]
|
50
|
+
attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service
|
51
|
+
attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
52
|
+
span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client)
|
53
|
+
ctx = OpenTelemetry::Trace.context_with_span(span)
|
54
|
+
datum[:otel_span] = span
|
55
|
+
datum[:otel_token] = OpenTelemetry::Context.attach(ctx)
|
56
|
+
OpenTelemetry.propagation.inject(datum[:headers])
|
57
|
+
@stack.request_call(datum)
|
58
|
+
end
|
59
|
+
|
60
|
+
def response_call(datum)
|
61
|
+
@stack.response_call(datum).tap do |d|
|
62
|
+
handle_response(d)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def error_call(datum)
|
67
|
+
handle_response(datum)
|
68
|
+
@stack.error_call(datum)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns a copy of the default stack with the trace middleware injected
|
72
|
+
def self.around_default_stack
|
73
|
+
::Excon.defaults[:middlewares].dup.tap do |default_stack|
|
74
|
+
# If the default stack contains a version of the trace middleware already...
|
75
|
+
existing_trace_middleware = default_stack.find { |m| m <= TracerMiddleware }
|
76
|
+
default_stack.delete(existing_trace_middleware) if existing_trace_middleware
|
77
|
+
# Inject after the ResponseParser middleware
|
78
|
+
response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i
|
79
|
+
default_stack.insert(response_middleware_index + 1, self)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def handle_response(datum)
|
86
|
+
datum.delete(:otel_span)&.tap do |span|
|
87
|
+
return unless span.recording?
|
88
|
+
|
89
|
+
if datum.key?(:response)
|
90
|
+
response = datum[:response]
|
91
|
+
span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response[:status])
|
92
|
+
span.set_attribute('http.response.status_code', response[:status])
|
93
|
+
span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response[:status].to_i)
|
94
|
+
end
|
95
|
+
|
96
|
+
if datum.key?(:error)
|
97
|
+
span.status = OpenTelemetry::Trace::Status.error('Request has failed')
|
98
|
+
span.record_exception(datum[:error])
|
99
|
+
end
|
100
|
+
|
101
|
+
span.finish
|
102
|
+
OpenTelemetry::Context.detach(datum.delete(:otel_token)) if datum.include?(:otel_token)
|
103
|
+
end
|
104
|
+
rescue StandardError => e
|
105
|
+
OpenTelemetry.handle_error(e)
|
106
|
+
end
|
107
|
+
|
108
|
+
def tracer
|
109
|
+
Excon::Instrumentation.instance.tracer
|
110
|
+
end
|
111
|
+
|
112
|
+
def untraced?(datum)
|
113
|
+
datum.key?(:otel_span) || Excon::Instrumentation.instance.untraced?(datum[:host])
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,111 @@
|
|
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
|
+
module Middlewares
|
11
|
+
module Old
|
12
|
+
# Excon middleware for instrumentation
|
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
|
+
# Constant for the HTTP status range
|
26
|
+
HTTP_STATUS_SUCCESS_RANGE = (100..399)
|
27
|
+
|
28
|
+
def request_call(datum)
|
29
|
+
return @stack.request_call(datum) if untraced?(datum)
|
30
|
+
|
31
|
+
http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]]
|
32
|
+
attributes = {
|
33
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => datum[:host],
|
34
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method,
|
35
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => datum[:scheme],
|
36
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => datum[:path],
|
37
|
+
OpenTelemetry::SemanticConventions::Trace::HTTP_URL => OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum)),
|
38
|
+
OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => datum[:hostname],
|
39
|
+
OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => datum[:port]
|
40
|
+
}
|
41
|
+
peer_service = Excon::Instrumentation.instance.config[:peer_service]
|
42
|
+
attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service
|
43
|
+
attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
44
|
+
span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client)
|
45
|
+
ctx = OpenTelemetry::Trace.context_with_span(span)
|
46
|
+
datum[:otel_span] = span
|
47
|
+
datum[:otel_token] = OpenTelemetry::Context.attach(ctx)
|
48
|
+
OpenTelemetry.propagation.inject(datum[:headers])
|
49
|
+
@stack.request_call(datum)
|
50
|
+
end
|
51
|
+
|
52
|
+
def response_call(datum)
|
53
|
+
@stack.response_call(datum).tap do |d|
|
54
|
+
handle_response(d)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def error_call(datum)
|
59
|
+
handle_response(datum)
|
60
|
+
@stack.error_call(datum)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns a copy of the default stack with the trace middleware injected
|
64
|
+
def self.around_default_stack
|
65
|
+
::Excon.defaults[:middlewares].dup.tap do |default_stack|
|
66
|
+
# If the default stack contains a version of the trace middleware already...
|
67
|
+
existing_trace_middleware = default_stack.find { |m| m <= TracerMiddleware }
|
68
|
+
default_stack.delete(existing_trace_middleware) if existing_trace_middleware
|
69
|
+
# Inject after the ResponseParser middleware
|
70
|
+
response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i
|
71
|
+
default_stack.insert(response_middleware_index + 1, self)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def handle_response(datum)
|
78
|
+
datum.delete(:otel_span)&.tap do |span|
|
79
|
+
return unless span.recording?
|
80
|
+
|
81
|
+
if datum.key?(:response)
|
82
|
+
response = datum[:response]
|
83
|
+
span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response[:status])
|
84
|
+
span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response[:status].to_i)
|
85
|
+
end
|
86
|
+
|
87
|
+
if datum.key?(:error)
|
88
|
+
span.status = OpenTelemetry::Trace::Status.error('Request has failed')
|
89
|
+
span.record_exception(datum[:error])
|
90
|
+
end
|
91
|
+
|
92
|
+
span.finish
|
93
|
+
OpenTelemetry::Context.detach(datum.delete(:otel_token)) if datum.include?(:otel_token)
|
94
|
+
end
|
95
|
+
rescue StandardError => e
|
96
|
+
OpenTelemetry.handle_error(e)
|
97
|
+
end
|
98
|
+
|
99
|
+
def tracer
|
100
|
+
Excon::Instrumentation.instance.tracer
|
101
|
+
end
|
102
|
+
|
103
|
+
def untraced?(datum)
|
104
|
+
datum.key?(:otel_span) || Excon::Instrumentation.instance.untraced?(datum[:host])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,111 @@
|
|
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
|
+
module Middlewares
|
11
|
+
module Stable
|
12
|
+
# Excon middleware for instrumentation
|
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
|
+
# Constant for the HTTP status range
|
26
|
+
HTTP_STATUS_SUCCESS_RANGE = (100..399)
|
27
|
+
|
28
|
+
def request_call(datum)
|
29
|
+
return @stack.request_call(datum) if untraced?(datum)
|
30
|
+
|
31
|
+
http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]]
|
32
|
+
attributes = {
|
33
|
+
'http.request.method' => http_method,
|
34
|
+
'url.scheme' => datum[:scheme],
|
35
|
+
'url.path' => datum[:path],
|
36
|
+
'url.full' => OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum)),
|
37
|
+
'server.address' => datum[:hostname],
|
38
|
+
'server.port' => datum[:port]
|
39
|
+
}
|
40
|
+
attributes['url.query'] = datum[:query] if datum[:query]
|
41
|
+
peer_service = Excon::Instrumentation.instance.config[:peer_service]
|
42
|
+
attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service
|
43
|
+
attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
44
|
+
span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client)
|
45
|
+
ctx = OpenTelemetry::Trace.context_with_span(span)
|
46
|
+
datum[:otel_span] = span
|
47
|
+
datum[:otel_token] = OpenTelemetry::Context.attach(ctx)
|
48
|
+
OpenTelemetry.propagation.inject(datum[:headers])
|
49
|
+
@stack.request_call(datum)
|
50
|
+
end
|
51
|
+
|
52
|
+
def response_call(datum)
|
53
|
+
@stack.response_call(datum).tap do |d|
|
54
|
+
handle_response(d)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def error_call(datum)
|
59
|
+
handle_response(datum)
|
60
|
+
@stack.error_call(datum)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns a copy of the default stack with the trace middleware injected
|
64
|
+
def self.around_default_stack
|
65
|
+
::Excon.defaults[:middlewares].dup.tap do |default_stack|
|
66
|
+
# If the default stack contains a version of the trace middleware already...
|
67
|
+
existing_trace_middleware = default_stack.find { |m| m <= TracerMiddleware }
|
68
|
+
default_stack.delete(existing_trace_middleware) if existing_trace_middleware
|
69
|
+
# Inject after the ResponseParser middleware
|
70
|
+
response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i
|
71
|
+
default_stack.insert(response_middleware_index + 1, self)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def handle_response(datum)
|
78
|
+
datum.delete(:otel_span)&.tap do |span|
|
79
|
+
return unless span.recording?
|
80
|
+
|
81
|
+
if datum.key?(:response)
|
82
|
+
response = datum[:response]
|
83
|
+
span.set_attribute('http.response.status_code', response[:status])
|
84
|
+
span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response[:status].to_i)
|
85
|
+
end
|
86
|
+
|
87
|
+
if datum.key?(:error)
|
88
|
+
span.status = OpenTelemetry::Trace::Status.error('Request has failed')
|
89
|
+
span.record_exception(datum[:error])
|
90
|
+
end
|
91
|
+
|
92
|
+
span.finish
|
93
|
+
OpenTelemetry::Context.detach(datum.delete(:otel_token)) if datum.include?(:otel_token)
|
94
|
+
end
|
95
|
+
rescue StandardError => e
|
96
|
+
OpenTelemetry.handle_error(e)
|
97
|
+
end
|
98
|
+
|
99
|
+
def tracer
|
100
|
+
Excon::Instrumentation.instance.tracer
|
101
|
+
end
|
102
|
+
|
103
|
+
def untraced?(datum)
|
104
|
+
datum.key?(:otel_span) || Excon::Instrumentation.instance.untraced?(datum[:host])
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,65 @@
|
|
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
|
+
module Patches
|
11
|
+
module Dup
|
12
|
+
# Module to prepend to an Excon Socket for instrumentation
|
13
|
+
module Socket
|
14
|
+
private
|
15
|
+
|
16
|
+
def connect
|
17
|
+
return super if untraced?
|
18
|
+
|
19
|
+
if @data[:proxy]
|
20
|
+
conn_address = @data.dig(:proxy, :hostname)
|
21
|
+
conn_port = @data.dig(:proxy, :port)
|
22
|
+
else
|
23
|
+
conn_address = @data[:hostname]
|
24
|
+
conn_port = @port
|
25
|
+
end
|
26
|
+
|
27
|
+
attributes = {
|
28
|
+
OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => conn_address,
|
29
|
+
OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => conn_port,
|
30
|
+
'server.address' => conn_address,
|
31
|
+
'server.port' => conn_port
|
32
|
+
}.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
33
|
+
|
34
|
+
if is_a?(::Excon::SSLSocket) && @data[:proxy]
|
35
|
+
span_name = 'CONNECT'
|
36
|
+
span_kind = :client
|
37
|
+
else
|
38
|
+
span_name = 'connect'
|
39
|
+
span_kind = :internal
|
40
|
+
end
|
41
|
+
|
42
|
+
tracer.in_span(span_name, attributes: attributes, kind: span_kind) do
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def tracer
|
48
|
+
Excon::Instrumentation.instance.tracer
|
49
|
+
end
|
50
|
+
|
51
|
+
def untraced?
|
52
|
+
address = if @data[:proxy]
|
53
|
+
@data.dig(:proxy, :hostname)
|
54
|
+
else
|
55
|
+
@data[:hostname]
|
56
|
+
end
|
57
|
+
|
58
|
+
Excon::Instrumentation.instance.untraced?(address)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,60 @@
|
|
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
|
+
module Patches
|
11
|
+
module Old
|
12
|
+
# Module to prepend to an Excon Socket for instrumentation
|
13
|
+
module Socket
|
14
|
+
private
|
15
|
+
|
16
|
+
def connect
|
17
|
+
return super if untraced?
|
18
|
+
|
19
|
+
if @data[:proxy]
|
20
|
+
conn_address = @data.dig(:proxy, :hostname)
|
21
|
+
conn_port = @data.dig(:proxy, :port)
|
22
|
+
else
|
23
|
+
conn_address = @data[:hostname]
|
24
|
+
conn_port = @port
|
25
|
+
end
|
26
|
+
|
27
|
+
attributes = { OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => conn_address, OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => conn_port }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
28
|
+
|
29
|
+
if is_a?(::Excon::SSLSocket) && @data[:proxy]
|
30
|
+
span_name = 'HTTP CONNECT'
|
31
|
+
span_kind = :client
|
32
|
+
else
|
33
|
+
span_name = 'connect'
|
34
|
+
span_kind = :internal
|
35
|
+
end
|
36
|
+
|
37
|
+
tracer.in_span(span_name, attributes: attributes, kind: span_kind) do
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def tracer
|
43
|
+
Excon::Instrumentation.instance.tracer
|
44
|
+
end
|
45
|
+
|
46
|
+
def untraced?
|
47
|
+
address = if @data[:proxy]
|
48
|
+
@data.dig(:proxy, :hostname)
|
49
|
+
else
|
50
|
+
@data[:hostname]
|
51
|
+
end
|
52
|
+
|
53
|
+
Excon::Instrumentation.instance.untraced?(address)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,60 @@
|
|
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
|
+
module Patches
|
11
|
+
module Stable
|
12
|
+
# Module to prepend to an Excon Socket for instrumentation
|
13
|
+
module Socket
|
14
|
+
private
|
15
|
+
|
16
|
+
def connect
|
17
|
+
return super if untraced?
|
18
|
+
|
19
|
+
if @data[:proxy]
|
20
|
+
conn_address = @data.dig(:proxy, :hostname)
|
21
|
+
conn_port = @data.dig(:proxy, :port)
|
22
|
+
else
|
23
|
+
conn_address = @data[:hostname]
|
24
|
+
conn_port = @port
|
25
|
+
end
|
26
|
+
|
27
|
+
attributes = { 'server.address' => conn_address, 'server.port' => conn_port }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
28
|
+
|
29
|
+
if is_a?(::Excon::SSLSocket) && @data[:proxy]
|
30
|
+
span_name = 'CONNECT'
|
31
|
+
span_kind = :client
|
32
|
+
else
|
33
|
+
span_name = 'connect'
|
34
|
+
span_kind = :internal
|
35
|
+
end
|
36
|
+
|
37
|
+
tracer.in_span(span_name, attributes: attributes, kind: span_kind) do
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def tracer
|
43
|
+
Excon::Instrumentation.instance.tracer
|
44
|
+
end
|
45
|
+
|
46
|
+
def untraced?
|
47
|
+
address = if @data[:proxy]
|
48
|
+
@data.dig(:proxy, :hostname)
|
49
|
+
else
|
50
|
+
@data[:hostname]
|
51
|
+
end
|
52
|
+
|
53
|
+
Excon::Instrumentation.instance.untraced?(address)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
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.
|
4
|
+
version: 0.24.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-
|
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,146 +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: webmock
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - "~>"
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: 3.24.0
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - "~>"
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: 3.24.0
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: yard
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - "~>"
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0.9'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: '0.9'
|
181
41
|
description: Excon instrumentation for the OpenTelemetry framework
|
182
42
|
email:
|
183
43
|
- cncf-opentelemetry-contributors@lists.cncf.io
|
@@ -194,17 +54,21 @@ files:
|
|
194
54
|
- lib/opentelemetry/instrumentation/concerns/untraced_hosts.rb
|
195
55
|
- lib/opentelemetry/instrumentation/excon.rb
|
196
56
|
- lib/opentelemetry/instrumentation/excon/instrumentation.rb
|
197
|
-
- lib/opentelemetry/instrumentation/excon/middlewares/tracer_middleware.rb
|
198
|
-
- lib/opentelemetry/instrumentation/excon/
|
57
|
+
- lib/opentelemetry/instrumentation/excon/middlewares/dup/tracer_middleware.rb
|
58
|
+
- lib/opentelemetry/instrumentation/excon/middlewares/old/tracer_middleware.rb
|
59
|
+
- lib/opentelemetry/instrumentation/excon/middlewares/stable/tracer_middleware.rb
|
60
|
+
- lib/opentelemetry/instrumentation/excon/patches/dup/socket.rb
|
61
|
+
- lib/opentelemetry/instrumentation/excon/patches/old/socket.rb
|
62
|
+
- lib/opentelemetry/instrumentation/excon/patches/stable/socket.rb
|
199
63
|
- lib/opentelemetry/instrumentation/excon/version.rb
|
200
64
|
homepage: https://github.com/open-telemetry/opentelemetry-ruby-contrib
|
201
65
|
licenses:
|
202
66
|
- Apache-2.0
|
203
67
|
metadata:
|
204
|
-
changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.
|
68
|
+
changelog_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.24.0/file/CHANGELOG.md
|
205
69
|
source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/excon
|
206
70
|
bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues
|
207
|
-
documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.
|
71
|
+
documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-excon/0.24.0
|
208
72
|
post_install_message:
|
209
73
|
rdoc_options: []
|
210
74
|
require_paths:
|
@@ -1,109 +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 Excon
|
10
|
-
module Middlewares
|
11
|
-
# Excon middleware for instrumentation
|
12
|
-
class TracerMiddleware < ::Excon::Middleware::Base
|
13
|
-
HTTP_METHODS_TO_UPPERCASE = %w[connect delete get head options patch post put trace].each_with_object({}) do |method, hash|
|
14
|
-
uppercase_method = method.upcase
|
15
|
-
hash[method] = uppercase_method
|
16
|
-
hash[method.to_sym] = uppercase_method
|
17
|
-
hash[uppercase_method] = uppercase_method
|
18
|
-
end.freeze
|
19
|
-
|
20
|
-
HTTP_METHODS_TO_SPAN_NAMES = HTTP_METHODS_TO_UPPERCASE.values.each_with_object({}) do |uppercase_method, hash|
|
21
|
-
hash[uppercase_method] ||= "HTTP #{uppercase_method}"
|
22
|
-
end.freeze
|
23
|
-
|
24
|
-
# Constant for the HTTP status range
|
25
|
-
HTTP_STATUS_SUCCESS_RANGE = (100..399)
|
26
|
-
|
27
|
-
def request_call(datum)
|
28
|
-
return @stack.request_call(datum) if untraced?(datum)
|
29
|
-
|
30
|
-
http_method = HTTP_METHODS_TO_UPPERCASE[datum[:method]]
|
31
|
-
attributes = {
|
32
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => datum[:host],
|
33
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => http_method,
|
34
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => datum[:scheme],
|
35
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => datum[:path],
|
36
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_URL => OpenTelemetry::Common::Utilities.cleanse_url(::Excon::Utils.request_uri(datum)),
|
37
|
-
OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => datum[:hostname],
|
38
|
-
OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => datum[:port]
|
39
|
-
}
|
40
|
-
peer_service = Excon::Instrumentation.instance.config[:peer_service]
|
41
|
-
attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = peer_service if peer_service
|
42
|
-
attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
43
|
-
span = tracer.start_span(HTTP_METHODS_TO_SPAN_NAMES[http_method], attributes: attributes, kind: :client)
|
44
|
-
ctx = OpenTelemetry::Trace.context_with_span(span)
|
45
|
-
datum[:otel_span] = span
|
46
|
-
datum[:otel_token] = OpenTelemetry::Context.attach(ctx)
|
47
|
-
OpenTelemetry.propagation.inject(datum[:headers])
|
48
|
-
@stack.request_call(datum)
|
49
|
-
end
|
50
|
-
|
51
|
-
def response_call(datum)
|
52
|
-
@stack.response_call(datum).tap do |d|
|
53
|
-
handle_response(d)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def error_call(datum)
|
58
|
-
handle_response(datum)
|
59
|
-
@stack.error_call(datum)
|
60
|
-
end
|
61
|
-
|
62
|
-
# Returns a copy of the default stack with the trace middleware injected
|
63
|
-
def self.around_default_stack
|
64
|
-
::Excon.defaults[:middlewares].dup.tap do |default_stack|
|
65
|
-
# If the default stack contains a version of the trace middleware already...
|
66
|
-
existing_trace_middleware = default_stack.find { |m| m <= TracerMiddleware }
|
67
|
-
default_stack.delete(existing_trace_middleware) if existing_trace_middleware
|
68
|
-
# Inject after the ResponseParser middleware
|
69
|
-
response_middleware_index = default_stack.index(::Excon::Middleware::ResponseParser).to_i
|
70
|
-
default_stack.insert(response_middleware_index + 1, self)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
private
|
75
|
-
|
76
|
-
def handle_response(datum)
|
77
|
-
datum.delete(:otel_span)&.tap do |span|
|
78
|
-
return unless span.recording?
|
79
|
-
|
80
|
-
if datum.key?(:response)
|
81
|
-
response = datum[:response]
|
82
|
-
span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response[:status])
|
83
|
-
span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response[:status].to_i)
|
84
|
-
end
|
85
|
-
|
86
|
-
if datum.key?(:error)
|
87
|
-
span.status = OpenTelemetry::Trace::Status.error('Request has failed')
|
88
|
-
span.record_exception(datum[:error])
|
89
|
-
end
|
90
|
-
|
91
|
-
span.finish
|
92
|
-
OpenTelemetry::Context.detach(datum.delete(:otel_token)) if datum.include?(:otel_token)
|
93
|
-
end
|
94
|
-
rescue StandardError => e
|
95
|
-
OpenTelemetry.handle_error(e)
|
96
|
-
end
|
97
|
-
|
98
|
-
def tracer
|
99
|
-
Excon::Instrumentation.instance.tracer
|
100
|
-
end
|
101
|
-
|
102
|
-
def untraced?(datum)
|
103
|
-
datum.key?(:otel_span) || Excon::Instrumentation.instance.untraced?(datum[:host])
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
@@ -1,58 +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 Excon
|
10
|
-
module Patches
|
11
|
-
# Module to prepend to an Excon Socket for instrumentation
|
12
|
-
module Socket
|
13
|
-
private
|
14
|
-
|
15
|
-
def connect
|
16
|
-
return super if untraced?
|
17
|
-
|
18
|
-
if @data[:proxy]
|
19
|
-
conn_address = @data.dig(:proxy, :hostname)
|
20
|
-
conn_port = @data.dig(:proxy, :port)
|
21
|
-
else
|
22
|
-
conn_address = @data[:hostname]
|
23
|
-
conn_port = @port
|
24
|
-
end
|
25
|
-
|
26
|
-
attributes = { OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => conn_address, OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => conn_port }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes)
|
27
|
-
|
28
|
-
if is_a?(::Excon::SSLSocket) && @data[:proxy]
|
29
|
-
span_name = 'HTTP CONNECT'
|
30
|
-
span_kind = :client
|
31
|
-
else
|
32
|
-
span_name = 'connect'
|
33
|
-
span_kind = :internal
|
34
|
-
end
|
35
|
-
|
36
|
-
tracer.in_span(span_name, attributes: attributes, kind: span_kind) do
|
37
|
-
super
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def tracer
|
42
|
-
Excon::Instrumentation.instance.tracer
|
43
|
-
end
|
44
|
-
|
45
|
-
def untraced?
|
46
|
-
address = if @data[:proxy]
|
47
|
-
@data.dig(:proxy, :hostname)
|
48
|
-
else
|
49
|
-
@data[:hostname]
|
50
|
-
end
|
51
|
-
|
52
|
-
Excon::Instrumentation.instance.untraced?(address)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|