Skip to content

Commit d0d7534

Browse files
authored
Merge branch 'main' into auto-instrumentation
2 parents 1e8c2b2 + 7837db8 commit d0d7534

File tree

27 files changed

+1064
-159
lines changed

27 files changed

+1064
-159
lines changed

.github/workflows/ci-instrumentation-with-services.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ jobs:
157157
ZOOKEEPER_CLIENT_PORT: 2181
158158
ZOOKEEPER_TICK_TIME: 2000
159159
kafka:
160-
image: confluentinc/cp-kafka:latest
160+
image: confluentinc/cp-kafka:7.9.1
161161
ports:
162162
- 9092:9092
163163
- 29092:29092

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ services:
226226
ZOOKEEPER_TICK_TIME: 2000
227227

228228
kafka:
229-
image: confluentinc/cp-kafka:latest
229+
image: confluentinc/cp-kafka:7.9.1
230230
ports:
231231
- "9092:9092"
232232
- "29092:29092"

instrumentation/action_pack/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Release History: opentelemetry-instrumentation-action_pack
22

3+
### v0.12.3 / 2025-06-16
4+
5+
* FIXED: Action_pack always assuming sdk spans
6+
7+
### v0.12.2 / 2025-06-04
8+
9+
* FIXED: Rack span class naming
10+
311
### v0.12.1 / 2025-05-07
412

513
* FIXED: Account for `nil` routes

instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/handlers/action_controller.rb

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,35 +23,9 @@ def initialize(config)
2323
# @param payload [Hash] the payload passed as a method argument
2424
# @return [Hash] the payload passed as a method argument
2525
def start(_name, _id, payload)
26-
span_name, attributes = to_span_name_and_attributes(payload)
27-
2826
span = OpenTelemetry::Instrumentation::Rack.current_span
29-
span.name = span_name
30-
span.add_attributes(attributes)
31-
rescue StandardError => e
32-
OpenTelemetry.handle_error(exception: e)
33-
end
34-
35-
# Invoked by ActiveSupport::Notifications at the end of the instrumentation block
36-
#
37-
# @param _name [String] of the event (unused)
38-
# @param _id [String] of the event (unused)
39-
# @param payload [Hash] the payload passed as a method argument
40-
# @return [Hash] the payload passed as a method argument
41-
def finish(_name, _id, payload)
42-
span = OpenTelemetry::Instrumentation::Rack.current_span
43-
span.record_exception(payload[:exception_object]) if payload[:exception_object]
44-
rescue StandardError => e
45-
OpenTelemetry.handle_error(exception: e)
46-
end
47-
48-
private
27+
return unless span.recording?
4928

50-
# Extracts the span name and attributes from the payload
51-
#
52-
# @param payload [Hash] the payload passed from ActiveSupport::Notifications
53-
# @return [Array<String, Hash>] the span name and attributes
54-
def to_span_name_and_attributes(payload)
5529
request = payload[:request]
5630
# It seems that there are cases in Rails functional tests where it bypasses the routing system and the `action_dispatch.route_uri_pattern` header not being set.
5731
# Our Test suite executes the routing system so we are unable to recreate this error case.
@@ -66,12 +40,33 @@ def to_span_name_and_attributes(payload)
6640
attributes[OpenTelemetry::SemanticConventions::Trace::HTTP_TARGET] = request.filtered_path if request.filtered_path != request.fullpath
6741

6842
if @span_naming == :semconv
69-
return ["#{request.method} #{http_route}", attributes] if http_route
70-
71-
return ["#{request.method} /#{payload.dig(:params, :controller)}/#{payload.dig(:params, :action)}", attributes]
43+
span.name = if http_route
44+
"#{request.method} #{http_route}"
45+
else
46+
"#{request.method} /#{payload.dig(:params, :controller)}/#{payload.dig(:params, :action)}"
47+
end
48+
# If there is an exception we want to keep the original span name
49+
# so it is easier to see where the request was routed to.
50+
elsif !request.env['action_dispatch.exception']
51+
span.name = "#{payload[:controller]}##{payload[:action]}"
7252
end
7353

74-
["#{payload[:controller]}##{payload[:action]}", attributes]
54+
span.add_attributes(attributes)
55+
rescue StandardError => e
56+
OpenTelemetry.handle_error(exception: e)
57+
end
58+
59+
# Invoked by ActiveSupport::Notifications at the end of the instrumentation block
60+
#
61+
# @param _name [String] of the event (unused)
62+
# @param _id [String] of the event (unused)
63+
# @param payload [Hash] the payload passed as a method argument
64+
# @return [Hash] the payload passed as a method argument
65+
def finish(_name, _id, payload)
66+
span = OpenTelemetry::Instrumentation::Rack.current_span
67+
span.record_exception(payload[:exception_object]) if payload[:exception_object]
68+
rescue StandardError => e
69+
OpenTelemetry.handle_error(exception: e)
7570
end
7671
end
7772
end

instrumentation/action_pack/lib/opentelemetry/instrumentation/action_pack/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
module OpenTelemetry
88
module Instrumentation
99
module ActionPack
10-
VERSION = '0.12.1'
10+
VERSION = '0.12.3'
1111
end
1212
end
1313
end

instrumentation/action_pack/test/opentelemetry/instrumentation/action_pack/handlers/action_controller_test.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,12 @@
215215

216216
describe 'when the application has exceptions_app configured' do
217217
let(:rails_app) { AppConfig.initialize_app(use_exceptions_app: true) }
218+
let(:config) { { span_naming: :class } }
218219

219220
it 'does not overwrite the span name from the controller that raised' do
220221
get 'internal_server_error'
221222

222-
_(span.name).must_match(/^GET/)
223+
_(span.name).must_equal 'ExampleController#internal_server_error'
223224
_(span.kind).must_equal :server
224225
_(span.status.ok?).must_equal false
225226

@@ -235,6 +236,12 @@
235236
_(span.attributes['code.namespace']).must_equal 'ExceptionsController'
236237
_(span.attributes['code.function']).must_equal 'show'
237238
end
239+
240+
it 'does not raise with api/non recording spans' do
241+
with_sampler(OpenTelemetry::SDK::Trace::Samplers::ALWAYS_OFF) do
242+
get 'internal_server_error'
243+
end
244+
end
238245
end
239246

240247
it 'sets filters `http.target`' do

instrumentation/action_pack/test/test_helper.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@
2424
c.use 'OpenTelemetry::Instrumentation::ActionPack'
2525
c.add_span_processor span_processor
2626
end
27+
28+
def with_sampler(sampler)
29+
previous_sampler = OpenTelemetry.tracer_provider.sampler
30+
OpenTelemetry.tracer_provider.sampler = sampler
31+
yield
32+
ensure
33+
OpenTelemetry.tracer_provider.sampler = previous_sampler
34+
end

instrumentation/http/Appraisals

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@
44
#
55
# SPDX-License-Identifier: Apache-2.0
66

7-
appraise 'http-4.4' do
8-
gem 'http', '~> 4.4.0'
9-
end
7+
# To faclitate HTTP semantic convention stability migration, we are using
8+
# appraisal to test the different semantic convention modes along with different
9+
# HTTP gem versions. For more information on the semantic convention modes, see:
10+
# https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/
11+
12+
semconv_stability = %w[dup stable old]
13+
14+
semconv_stability.each do |mode|
15+
appraise "http-4.4.0-#{mode}" do
16+
gem 'http', '~> 4.4.0'
17+
end
1018

11-
appraise 'http-3.3.0' do
12-
gem 'http', '~> 3.3.0'
19+
appraise "http-3.3.0-#{mode}" do
20+
gem 'http', '~> 3.3.0'
21+
end
1322
end

instrumentation/http/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,19 @@ The `opentelemetry-instrumentation-http` gem is distributed under the Apache 2.0
6464
[community-meetings]: https://github.com/open-telemetry/community#community-meetings
6565
[slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY
6666
[discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions
67+
68+
## HTTP semantic convention stability
69+
70+
In the OpenTelemetry ecosystem, HTTP semantic conventions have now reached a stable state. However, the initial HTTP instrumentation was introduced before this stability was achieved, which resulted in HTTP attributes being based on an older version of the semantic conventions.
71+
72+
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.
73+
74+
When setting the value for `OTEL_SEMCONV_STABILITY_OPT_IN`, you can specify which conventions you wish to adopt:
75+
76+
- `http` - Emits the stable HTTP and networking conventions and ceases emitting the old conventions previously emitted by the instrumentation.
77+
- `http/dup` - Emits both the old and stable HTTP and networking conventions, enabling a phased rollout of the stable semantic conventions.
78+
- Default behavior (in the absence of either value) is to continue emitting the old HTTP and networking conventions the instrumentation previously emitted.
79+
80+
During the transition from old to stable conventions, HTTP instrumentation code comes in three patch versions: `dup`, `old`, and `stable`. These versions are identical except for the attributes they send. Any changes to HTTP instrumentation should consider all three patches.
81+
82+
For additional information on migration, please refer to our [documentation](https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/).

instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ module HTTP
1010
# The Instrumentation class contains logic to detect and install the Http instrumentation
1111
class Instrumentation < OpenTelemetry::Instrumentation::Base
1212
install do |_config|
13-
require_dependencies
14-
patch
13+
patch_type = determine_semconv
14+
send(:"require_dependencies_#{patch_type}")
15+
send(:"patch_#{patch_type}")
1516
end
1617

1718
present do
@@ -20,14 +21,47 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base
2021

2122
option :span_name_formatter, default: nil, validate: :callable
2223

23-
def patch
24-
::HTTP::Client.prepend(Patches::Client)
25-
::HTTP::Connection.prepend(Patches::Connection)
24+
def determine_semconv
25+
stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', '')
26+
values = stability_opt_in.split(',').map(&:strip)
27+
28+
if values.include?('http/dup')
29+
'dup'
30+
elsif values.include?('http')
31+
'stable'
32+
else
33+
'old'
34+
end
35+
end
36+
37+
def patch_old
38+
::HTTP::Client.prepend(Patches::Old::Client)
39+
::HTTP::Connection.prepend(Patches::Old::Connection)
40+
end
41+
42+
def patch_dup
43+
::HTTP::Client.prepend(Patches::Dup::Client)
44+
::HTTP::Connection.prepend(Patches::Dup::Connection)
45+
end
46+
47+
def patch_stable
48+
::HTTP::Client.prepend(Patches::Stable::Client)
49+
::HTTP::Connection.prepend(Patches::Stable::Connection)
50+
end
51+
52+
def require_dependencies_dup
53+
require_relative 'patches/dup/client'
54+
require_relative 'patches/dup/connection'
55+
end
56+
57+
def require_dependencies_old
58+
require_relative 'patches/old/client'
59+
require_relative 'patches/old/connection'
2660
end
2761

28-
def require_dependencies
29-
require_relative 'patches/client'
30-
require_relative 'patches/connection'
62+
def require_dependencies_stable
63+
require_relative 'patches/stable/client'
64+
require_relative 'patches/stable/connection'
3165
end
3266
end
3367
end

0 commit comments

Comments
 (0)