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