opentelemetry-instrumentation-httpx 0.2.0 → 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 +8 -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 -173
- data/lib/opentelemetry/instrumentation/httpx/plugin.rb +0 -95
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,13 @@
|
|
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
|
+
|
7
|
+
### v0.2.1 / 2025-04-29
|
8
|
+
|
9
|
+
* FIXED: Httpx instrumentation trace context propagation
|
10
|
+
|
3
11
|
### v0.2.0 / 2025-01-16
|
4
12
|
|
5
13
|
* BREAKING CHANGE: Set minimum supported version to Ruby 3.1
|
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
|
@@ -38,174 +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: rake
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '13.0'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '13.0'
|
125
|
-
- !ruby/object:Gem::Dependency
|
126
|
-
name: rspec-mocks
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
128
|
-
requirements:
|
129
|
-
- - ">="
|
130
|
-
- !ruby/object:Gem::Version
|
131
|
-
version: '0'
|
132
|
-
type: :development
|
133
|
-
prerelease: false
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
135
|
-
requirements:
|
136
|
-
- - ">="
|
137
|
-
- !ruby/object:Gem::Version
|
138
|
-
version: '0'
|
139
|
-
- !ruby/object:Gem::Dependency
|
140
|
-
name: rubocop
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
142
|
-
requirements:
|
143
|
-
- - "~>"
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
version: 1.69.1
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
149
|
-
requirements:
|
150
|
-
- - "~>"
|
151
|
-
- !ruby/object:Gem::Version
|
152
|
-
version: 1.69.1
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: rubocop-performance
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - "~>"
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: 1.23.0
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - "~>"
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: 1.23.0
|
167
|
-
- !ruby/object:Gem::Dependency
|
168
|
-
name: simplecov
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
170
|
-
requirements:
|
171
|
-
- - "~>"
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: 0.17.1
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
177
|
-
requirements:
|
178
|
-
- - "~>"
|
179
|
-
- !ruby/object:Gem::Version
|
180
|
-
version: 0.17.1
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: webmock
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
184
|
-
requirements:
|
185
|
-
- - "~>"
|
186
|
-
- !ruby/object:Gem::Version
|
187
|
-
version: 3.24.0
|
188
|
-
type: :development
|
189
|
-
prerelease: false
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
191
|
-
requirements:
|
192
|
-
- - "~>"
|
193
|
-
- !ruby/object:Gem::Version
|
194
|
-
version: 3.24.0
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
|
-
name: yard
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
198
|
-
requirements:
|
199
|
-
- - "~>"
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: '0.9'
|
202
|
-
type: :development
|
203
|
-
prerelease: false
|
204
|
-
version_requirements: !ruby/object:Gem::Requirement
|
205
|
-
requirements:
|
206
|
-
- - "~>"
|
207
|
-
- !ruby/object:Gem::Version
|
208
|
-
version: '0.9'
|
209
41
|
description: HTTPX instrumentation for the OpenTelemetry framework
|
210
42
|
email:
|
211
43
|
- cncf-opentelemetry-contributors@lists.cncf.io
|
@@ -220,17 +52,19 @@ files:
|
|
220
52
|
- lib/opentelemetry-instrumentation-httpx.rb
|
221
53
|
- lib/opentelemetry/instrumentation.rb
|
222
54
|
- lib/opentelemetry/instrumentation/httpx.rb
|
55
|
+
- lib/opentelemetry/instrumentation/httpx/dup/plugin.rb
|
223
56
|
- lib/opentelemetry/instrumentation/httpx/instrumentation.rb
|
224
|
-
- lib/opentelemetry/instrumentation/httpx/plugin.rb
|
57
|
+
- lib/opentelemetry/instrumentation/httpx/old/plugin.rb
|
58
|
+
- lib/opentelemetry/instrumentation/httpx/stable/plugin.rb
|
225
59
|
- lib/opentelemetry/instrumentation/httpx/version.rb
|
226
60
|
homepage: https://github.com/open-telemetry/opentelemetry-ruby-contrib
|
227
61
|
licenses:
|
228
62
|
- Apache-2.0
|
229
63
|
metadata:
|
230
|
-
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
|
231
65
|
source_code_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/tree/main/instrumentation/http
|
232
66
|
bug_tracker_uri: https://github.com/open-telemetry/opentelemetry-ruby-contrib/issues
|
233
|
-
documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.
|
67
|
+
documentation_uri: https://rubydoc.info/gems/opentelemetry-instrumentation-httpx/0.3.0
|
234
68
|
post_install_message:
|
235
69
|
rdoc_options: []
|
236
70
|
require_paths:
|
@@ -1,95 +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
|
-
class RequestTracer
|
14
|
-
# Constant for the HTTP status range
|
15
|
-
HTTP_STATUS_SUCCESS_RANGE = (100..399)
|
16
|
-
|
17
|
-
def initialize(request)
|
18
|
-
@request = request
|
19
|
-
end
|
20
|
-
|
21
|
-
def call
|
22
|
-
@request.on(:response, &method(:finish)) # rubocop:disable Performance/MethodObjectAsBlock
|
23
|
-
|
24
|
-
uri = @request.uri
|
25
|
-
request_method = @request.verb
|
26
|
-
span_name = "HTTP #{request_method}"
|
27
|
-
|
28
|
-
attributes = {
|
29
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_HOST => uri.host,
|
30
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_METHOD => request_method,
|
31
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_SCHEME => uri.scheme,
|
32
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET => uri.path,
|
33
|
-
OpenTelemetry::SemanticConventions::Trace::HTTP_URL => "#{uri.scheme}://#{uri.host}",
|
34
|
-
OpenTelemetry::SemanticConventions::Trace::NET_PEER_NAME => uri.host,
|
35
|
-
OpenTelemetry::SemanticConventions::Trace::NET_PEER_PORT => uri.port
|
36
|
-
}
|
37
|
-
config = HTTPX::Instrumentation.instance.config
|
38
|
-
attributes[OpenTelemetry::SemanticConventions::Trace::PEER_SERVICE] = config[:peer_service] if config[:peer_service]
|
39
|
-
attributes.merge!(
|
40
|
-
OpenTelemetry::Common::HTTP::ClientContext.attributes
|
41
|
-
)
|
42
|
-
|
43
|
-
@span = tracer.start_span(span_name, attributes: attributes, kind: :client)
|
44
|
-
trace_ctx = OpenTelemetry::Trace.context_with_span(@span)
|
45
|
-
@trace_token = OpenTelemetry::Context.attach(trace_ctx)
|
46
|
-
|
47
|
-
OpenTelemetry.propagation.inject(@request.headers)
|
48
|
-
rescue StandardError => e
|
49
|
-
OpenTelemetry.handle_error(exception: e)
|
50
|
-
end
|
51
|
-
|
52
|
-
def finish(response)
|
53
|
-
return unless @span
|
54
|
-
|
55
|
-
if response.is_a?(::HTTPX::ErrorResponse)
|
56
|
-
@span.record_exception(response.error)
|
57
|
-
@span.status = Trace::Status.error("Unhandled exception of type: #{response.error.class}")
|
58
|
-
else
|
59
|
-
@span.set_attribute(OpenTelemetry::SemanticConventions::Trace::HTTP_STATUS_CODE, response.status)
|
60
|
-
@span.status = Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(response.status)
|
61
|
-
end
|
62
|
-
|
63
|
-
OpenTelemetry::Context.detach(@trace_token) if @trace_token
|
64
|
-
@span.finish
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def tracer
|
70
|
-
HTTPX::Instrumentation.instance.tracer
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
# HTTPX::Request overrides
|
75
|
-
module RequestMethods
|
76
|
-
def __otel_enable_trace!
|
77
|
-
return if @__otel_enable_trace
|
78
|
-
|
79
|
-
RequestTracer.new(self).call
|
80
|
-
@__otel_enable_trace = true
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# HTTPX::Connection overrides
|
85
|
-
module ConnectionMethods
|
86
|
-
def send(request)
|
87
|
-
request.__otel_enable_trace!
|
88
|
-
|
89
|
-
super
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|