From ca200a9361addcaaa9f2c25d563ff3b34fd7695e Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Wed, 14 May 2025 16:05:13 -0700 Subject: [PATCH 01/11] feat: WIP semcon file re-structure --- .../instrumentation/http/instrumentation.rb | 50 +++- .../instrumentation/http/patches/client.rb | 70 ----- .../http/patches/connection.rb | 33 --- .../http/patches/dup/client.rb | 84 ++++++ .../http/patches/dup/connection.rb | 40 +++ .../http/patches/old/client.rb | 73 ++++++ .../http/patches/old/connection.rb | 36 +++ .../http/patches/stable/client.rb | 75 ++++++ .../http/patches/stable/connection.rb | 36 +++ .../http/patches/dup/client_test.rb | 248 ++++++++++++++++++ .../http/patches/dup/connection_test.rb | 51 ++++ .../http/patches/{ => old}/client_test.rb | 6 +- .../http/patches/{ => old}/connection_test.rb | 6 +- .../http/patches/stable/client_test.rb | 198 ++++++++++++++ .../http/patches/stable/connection_test.rb | 47 ++++ 15 files changed, 935 insertions(+), 118 deletions(-) delete mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb delete mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb create mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb create mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/connection.rb create mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb create mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/connection.rb create mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/client.rb create mode 100644 instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/connection.rb create mode 100644 instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb create mode 100644 instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb rename instrumentation/http/test/instrumentation/http/patches/{ => old}/client_test.rb (96%) rename instrumentation/http/test/instrumentation/http/patches/{ => old}/connection_test.rb (82%) create mode 100644 instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb create mode 100644 instrumentation/http/test/instrumentation/http/patches/stable/connection_test.rb diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb index dfe3951bfc..84326684cd 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb @@ -10,8 +10,9 @@ module HTTP # The Instrumentation class contains logic to detect and install the Http instrumentation class Instrumentation < OpenTelemetry::Instrumentation::Base install do |_config| - require_dependencies - patch + patch_type = determine_semconv + send(:"require_dependencies_#{patch_type}") + send(:"patch_#{patch_type}") end present do @@ -20,16 +21,47 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base option :span_name_formatter, default: nil, validate: :callable - def patch - ::HTTP::Client.prepend(Patches::Client) - ::HTTP::Connection.prepend(Patches::Connection) + def determine_semconv + case ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil) + when 'http/dup' + 'dup' + when 'http' + 'stable' + else + 'old' + end end - def require_dependencies - require_relative 'patches/client' - require_relative 'patches/connection' + def patch_old + ::HTTP::Client.prepend(Patches::Old::Client) + ::HTTP::Connection.prepend(Patches::Old::Connection) + end + + def patch_dup + ::HTTP::Client.prepend(Patches::Dup::Client) + ::HTTP::Connection.prepend(Patches::Dup::Connection) + end + + def patch_stable + ::HTTP::Client.prepend(Patches::Stable::Client) + ::HTTP::Connection.prepend(Patches::Stable::Connection) + end + + def require_dependencies_dup + require_relative 'patches/dup/client' + require_relative 'patches/dup/connection' + end + + def require_dependencies_old + require_relative 'patches/old/client' + require_relative 'patches/old/connection' + end + + def require_dependencies_stable + require_relative 'patches/stable/client' + require_relative 'patches/stable/connection' end end end end -end +end \ No newline at end of file diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb deleted file mode 100644 index 1d98cb5c11..0000000000 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/client.rb +++ /dev/null @@ -1,70 +0,0 @@ -# frozen_string_literal: true - -# Copyright The OpenTelemetry Authors -# -# SPDX-License-Identifier: Apache-2.0 - -module OpenTelemetry - module Instrumentation - module HTTP - module Patches - # Module to prepend to HTTP::Client for instrumentation - module Client - # Constant for the HTTP status range - HTTP_STATUS_SUCCESS_RANGE = (100..399) - - def perform(req, options) - uri = req.uri - request_method = req.verb.to_s.upcase - span_name = create_request_span_name(request_method, uri.path) - - attributes = { - 'http.method' => request_method, - 'http.scheme' => uri.scheme, - 'http.target' => uri.path, - 'http.url' => "#{uri.scheme}://#{uri.host}", - 'net.peer.name' => uri.host, - 'net.peer.port' => uri.port - }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) - - tracer.in_span(span_name, attributes: attributes, kind: :client) do |span| - OpenTelemetry.propagation.inject(req.headers) - super.tap do |response| - annotate_span_with_response!(span, response) - end - end - end - - private - - def config - OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance.config - end - - def annotate_span_with_response!(span, response) - return unless response&.status - - status_code = response.status.to_i - span.set_attribute('http.status_code', status_code) - span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) - end - - def create_request_span_name(request_method, request_path) - if (implementation = config[:span_name_formatter]) - updated_span_name = implementation.call(request_method, request_path) - updated_span_name.is_a?(String) ? updated_span_name : "HTTP #{request_method}" - else - "HTTP #{request_method}" - end - rescue StandardError - "HTTP #{request_method}" - end - - def tracer - HTTP::Instrumentation.instance.tracer - end - end - end - end - end -end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb deleted file mode 100644 index 6e162886fa..0000000000 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/connection.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -# Copyright The OpenTelemetry Authors -# -# SPDX-License-Identifier: Apache-2.0 - -module OpenTelemetry - module Instrumentation - module HTTP - module Patches - # Module to prepend to HTTP::Connection for instrumentation - module Connection - def initialize(req, options) - attributes = { - 'net.peer.name' => req.uri.host, - 'net.peer.port' => req.uri.port - }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) - - tracer.in_span('HTTP CONNECT', attributes: attributes) do - super - end - end - - private - - def tracer - HTTP::Instrumentation.instance.tracer - end - end - end - end - end -end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb new file mode 100644 index 0000000000..d82776a3b1 --- /dev/null +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module HTTP + module Patches + # Module using old and stable HTTP semantic conventions + module Dup + # Module to prepend to HTTP::Client for instrumentation + module Client + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + + def perform(req, options) + uri = req.uri + request_method = req.verb.to_s.upcase + span_name = create_request_span_name(request_method, uri.path) + + attributes = { + # old semconv + 'http.method' => request_method, + 'http.scheme' => uri.scheme, + 'http.target' => uri.path, + 'http.url' => "#{uri.scheme}://#{uri.host}", + 'net.peer.name' => uri.host, + 'net.peer.port' => uri.port, + # stable semconv + 'http.request.method' => request_method, + 'url.scheme' => uri.scheme, + 'url.path' => uri.path, + 'url.full' => "#{uri.scheme}://#{uri.host}", + 'server.address' => uri.host, + 'server.port' => uri.port + } + attributes['url.query'] = uri.query unless uri.query.nil? + attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) + + tracer.in_span(span_name, attributes: attributes, kind: :client) do |span| + OpenTelemetry.propagation.inject(req.headers) + super.tap do |response| + annotate_span_with_response!(span, response) + end + end + end + + private + + def config + OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance.config + end + + def annotate_span_with_response!(span, response) + return unless response&.status + + status_code = response.status.to_i + span.set_attribute('http.status_code', status_code) #old semconv + span.set_attribute('http.response.status_code', status_code) #stable semconv + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) + end + + def create_request_span_name(request_method, request_path) + if (implementation = config[:span_name_formatter]) + updated_span_name = implementation.call(request_method, request_path) + updated_span_name.is_a?(String) ? updated_span_name : "HTTP #{request_method}" + else + "HTTP #{request_method}" + end + rescue StandardError + "HTTP #{request_method}" + end + + def tracer + HTTP::Instrumentation.instance.tracer + end + end + end + end + end + end +end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/connection.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/connection.rb new file mode 100644 index 0000000000..f807f59de8 --- /dev/null +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/connection.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module HTTP + module Patches + # Module using old and stable HTTP semantic conventions + module Dup + # Module to prepend to HTTP::Connection for instrumentation + module Connection + def initialize(req, options) + attributes = { + # old semconv + 'net.peer.name' => req.uri.host, + 'net.peer.port' => req.uri.port, + # stable semconv + 'server.address' => req.uri.host, + 'server.port' => req.uri.port + }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) + + tracer.in_span('HTTP CONNECT', attributes: attributes) do + super + end + end + + private + + def tracer + HTTP::Instrumentation.instance.tracer + end + end + end + end + end + end +end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb new file mode 100644 index 0000000000..aa47d12744 --- /dev/null +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module HTTP + module Patches + # Module using old HTTP semantic conventions + module Old + # Module to prepend to HTTP::Client for instrumentation + module Client + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + + def perform(req, options) + uri = req.uri + request_method = req.verb.to_s.upcase + span_name = create_request_span_name(request_method, uri.path) + + attributes = { + 'http.method' => request_method, + 'http.scheme' => uri.scheme, + 'http.target' => uri.path, + 'http.url' => "#{uri.scheme}://#{uri.host}", + 'net.peer.name' => uri.host, + 'net.peer.port' => uri.port + }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) + + tracer.in_span(span_name, attributes: attributes, kind: :client) do |span| + OpenTelemetry.propagation.inject(req.headers) + super.tap do |response| + annotate_span_with_response!(span, response) + end + end + end + + private + + def config + OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance.config + end + + def annotate_span_with_response!(span, response) + return unless response&.status + + status_code = response.status.to_i + span.set_attribute('http.status_code', status_code) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) + end + + def create_request_span_name(request_method, request_path) + if (implementation = config[:span_name_formatter]) + updated_span_name = implementation.call(request_method, request_path) + updated_span_name.is_a?(String) ? updated_span_name : "HTTP #{request_method}" + else + "HTTP #{request_method}" + end + rescue StandardError + "HTTP #{request_method}" + end + + def tracer + HTTP::Instrumentation.instance.tracer + end + end + end + end + end + end +end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/connection.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/connection.rb new file mode 100644 index 0000000000..b4f3b09bff --- /dev/null +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/connection.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module HTTP + module Patches + # Module using old HTTP semantic conventions + module Old + # Module to prepend to HTTP::Connection for instrumentation + module Connection + def initialize(req, options) + attributes = { + 'net.peer.name' => req.uri.host, + 'net.peer.port' => req.uri.port + }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) + + tracer.in_span('HTTP CONNECT', attributes: attributes) do + super + end + end + + private + + def tracer + HTTP::Instrumentation.instance.tracer + end + end + end + end + end + end +end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/client.rb new file mode 100644 index 0000000000..dda234b5c9 --- /dev/null +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/client.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module HTTP + module Patches + # Module using stable HTTP semantic conventions + module Stable + # Module to prepend to HTTP::Client for instrumentation + module Client + # Constant for the HTTP status range + HTTP_STATUS_SUCCESS_RANGE = (100..399) + + def perform(req, options) + uri = req.uri + request_method = req.verb.to_s.upcase + span_name = create_request_span_name(request_method, uri.path) + + attributes = { + 'http.request.method' => request_method, + 'url.scheme' => uri.scheme, + 'url.path' => uri.path, + 'url.full' => "#{uri.scheme}://#{uri.host}", + 'server.address' => uri.host, + 'server.port' => uri.port + } + attributes['url.query'] = uri.query unless uri.query.nil? + attributes.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) + + tracer.in_span(span_name, attributes: attributes, kind: :client) do |span| + OpenTelemetry.propagation.inject(req.headers) + super.tap do |response| + annotate_span_with_response!(span, response) + end + end + end + + private + + def config + OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance.config + end + + def annotate_span_with_response!(span, response) + return unless response&.status + + status_code = response.status.to_i + span.set_attribute('http.response.status_code', status_code) + span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) + end + + def create_request_span_name(request_method, request_path) + if (implementation = config[:span_name_formatter]) + updated_span_name = implementation.call(request_method, request_path) + updated_span_name.is_a?(String) ? updated_span_name : "HTTP #{request_method}" + else + "HTTP #{request_method}" + end + rescue StandardError + "HTTP #{request_method}" + end + + def tracer + HTTP::Instrumentation.instance.tracer + end + end + end + end + end + end +end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/connection.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/connection.rb new file mode 100644 index 0000000000..2797844b5b --- /dev/null +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/stable/connection.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +module OpenTelemetry + module Instrumentation + module HTTP + module Patches + # Module using stable HTTP semantic conventions + module Stable + # Module to prepend to HTTP::Connection for instrumentation + module Connection + def initialize(req, options) + attributes = { + 'server.address' => req.uri.host, + 'server.port' => req.uri.port + }.merge!(OpenTelemetry::Common::HTTP::ClientContext.attributes) + + tracer.in_span('HTTP CONNECT', attributes: attributes) do + super + end + end + + private + + def tracer + HTTP::Instrumentation.instance.tracer + end + end + end + end + end + end +end diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb new file mode 100644 index 0000000000..2f555b3e92 --- /dev/null +++ b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb @@ -0,0 +1,248 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +require_relative '../../../../../lib/opentelemetry/instrumentation/http' +require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/dup/client' + +describe OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Client do + let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } + let(:exporter) { EXPORTER } + let(:span) { exporter.finished_spans.first } + let(:config) do + { + span_name_formatter: span_name_formatter + } + end + let(:span_name_formatter) { nil } + + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' + + before do + exporter.reset + @orig_propagation = OpenTelemetry.propagation + propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator + OpenTelemetry.propagation = propagator + # simulate a fresh install: + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(config) + stub_request(:get, 'http://example.com/success').to_return(status: 200) + stub_request(:get, 'http://example.com/success?hello=there').to_return(status: 200) + stub_request(:post, 'http://example.com/failure').to_return(status: 500) + stub_request(:get, 'https://example.com/timeout').to_timeout + end + + after do + # Force re-install of instrumentation + instrumentation.instance_variable_set(:@installed, false) + OpenTelemetry.propagation = @orig_propagation + end + + describe '#perform' do + it 'traces a simple request' do + HTTP.get('http://example.com/success') + _(exporter.finished_spans.size).must_equal(1) + _(span.name).must_equal 'HTTP GET' + # Old semantic conventions + _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.scheme']).must_equal 'http' + _(span.attributes['http.status_code']).must_equal 200 + _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['net.peer.port']).must_equal 80 + # Stable semantic conventions + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + + assert_requested( + :get, + 'http://example.com/success', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + it 'after request with failure code' do + HTTP.post('http://example.com/failure') + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP POST' + # Old semantic conventions + _(span.attributes['http.method']).must_equal 'POST' + _(span.attributes['http.scheme']).must_equal 'http' + _(span.attributes['http.status_code']).must_equal 500 + _(span.attributes['http.target']).must_equal '/failure' + _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['net.peer.port']).must_equal 80 + # Stable semantic conventions + _(span.attributes['http.request.method']).must_equal 'POST' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 500 + _(span.attributes['url.path']).must_equal '/failure' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + assert_requested( + :post, + 'http://example.com/failure', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + it 'after request timeout' do + expect do + HTTP.get('https://example.com/timeout') + end.must_raise HTTP::TimeoutError + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET' + # Old semantic conventions + _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.scheme']).must_equal 'https' + _(span.attributes['http.status_code']).must_be_nil + _(span.attributes['http.target']).must_equal '/timeout' + _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['net.peer.port']).must_equal 443 + # Stable semantic conventions + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'https' + _(span.attributes['http.response.status_code']).must_be_nil + _(span.attributes['url.path']).must_equal '/timeout' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'https://example.com' + _(span.attributes['server.port']).must_equal 443 + _(span.attributes['url.query']).must_be_nil + _(span.status.code).must_equal( + OpenTelemetry::Trace::Status::ERROR + ) + _(span.status.description).must_equal( + 'Unhandled exception of type: HTTP::TimeoutError' + ) + assert_requested( + :get, + 'https://example.com/timeout', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + it 'merges http client attributes' do + OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do + HTTP.get('http://example.com/success?hello=there') + end + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET' + # Old semantic conventions + _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.scheme']).must_equal 'http' + _(span.attributes['http.status_code']).must_equal 200 + _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['peer.service']).must_equal 'foo' + # Stable semantic conventions + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_equal 'hello=there' + assert_requested( + :get, + 'http://example.com/success?hello=there', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + describe 'when span_name_formatter specified' do + let(:span_name_formatter) do + # demonstrate simple addition of path and string to span name: + lambda { |request_method, request_path| + "HTTP #{request_method} #{request_path} miniswan" + } + end + + it 'enriches the span' do + OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do + HTTP.get('http://example.com/success') + end + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET /success miniswan' + # Old semantic conventions + _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.scheme']).must_equal 'http' + _(span.attributes['http.status_code']).must_equal 200 + _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['peer.service']).must_equal 'foo' + # Stable semantic conventions + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + assert_requested( + :get, + 'http://example.com/success', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + end + describe 'when span_formatter specified and it errors' do + let(:span_name_formatter) do + # demonstrate simple addition of path and string to span name: + lambda { |_request_method, _request_path| + raise 'Something Bad' + } + end + + it 'provides a sane default' do + OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do + HTTP.get('http://example.com/success') + end + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET' + # Old semantic conventions + _(span.attributes['http.method']).must_equal 'GET' + _(span.attributes['http.scheme']).must_equal 'http' + _(span.attributes['http.status_code']).must_equal 200 + _(span.attributes['http.target']).must_equal '/success' + _(span.attributes['net.peer.name']).must_equal 'example.com' + _(span.attributes['net.peer.port']).must_equal 80 + _(span.attributes['peer.service']).must_equal 'foo' + # Stable semantic conventions + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + assert_requested( + :get, + 'http://example.com/success', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + end + end +end diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb new file mode 100644 index 0000000000..7eea34df6d --- /dev/null +++ b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +require_relative '../../../../../lib/opentelemetry/instrumentation/http' +require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/dup/connection' + +describe OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection do + let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } + let(:exporter) { EXPORTER } + let(:span) { exporter.finished_spans.first } + + before do + exporter.reset + instrumentation.install({}) + end + + # Force re-install of instrumentation + after do + instrumentation.instance_variable_set(:@installed, false) + end + + describe '#connect' do + it 'emits span on connect' do + WebMock.allow_net_connect! + TCPServer.open('localhost', 0) do |server| + Thread.start { server.accept } + port = server.addr[1] + + assert_raises(HTTP::TimeoutError) do + HTTP.timeout(connect: 0.1, write: 0.1, read: 0.1).get("http://localhost:#{port}/example") + end + end + + _(exporter.finished_spans.size).must_equal(2) + _(span.name).must_equal 'HTTP CONNECT' + # Old semantic conventions + _(span.attributes['net.peer.name']).must_equal('localhost') + _(span.attributes['net.peer.port']).wont_be_nil + # New semantic conventions + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).wont_be_nil + ensure + WebMock.disable_net_connect! + end + end +end diff --git a/instrumentation/http/test/instrumentation/http/patches/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb similarity index 96% rename from instrumentation/http/test/instrumentation/http/patches/client_test.rb rename to instrumentation/http/test/instrumentation/http/patches/old/client_test.rb index 8d62a5b07c..d1baaabc74 100644 --- a/instrumentation/http/test/instrumentation/http/patches/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb @@ -6,10 +6,10 @@ require 'test_helper' -require_relative '../../../../lib/opentelemetry/instrumentation/http' -require_relative '../../../../lib/opentelemetry/instrumentation/http/patches/client' +require_relative '../../../../../lib/opentelemetry/instrumentation/http' +require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/old/client' -describe OpenTelemetry::Instrumentation::HTTP::Patches::Client do +describe OpenTelemetry::Instrumentation::HTTP::Patches::Old::Client do let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } let(:exporter) { EXPORTER } let(:span) { exporter.finished_spans.first } diff --git a/instrumentation/http/test/instrumentation/http/patches/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/old/connection_test.rb similarity index 82% rename from instrumentation/http/test/instrumentation/http/patches/connection_test.rb rename to instrumentation/http/test/instrumentation/http/patches/old/connection_test.rb index fc0b2b2a49..a94cd16c8c 100644 --- a/instrumentation/http/test/instrumentation/http/patches/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/connection_test.rb @@ -6,10 +6,10 @@ require 'test_helper' -require_relative '../../../../lib/opentelemetry/instrumentation/http' -require_relative '../../../../lib/opentelemetry/instrumentation/http/patches/connection' +require_relative '../../../../../lib/opentelemetry/instrumentation/http' +require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/old/connection' -describe OpenTelemetry::Instrumentation::HTTP::Patches::Connection do +describe OpenTelemetry::Instrumentation::HTTP::Patches::Old::Connection do let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } let(:exporter) { EXPORTER } let(:span) { exporter.finished_spans.first } diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb new file mode 100644 index 0000000000..f7d152d98e --- /dev/null +++ b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb @@ -0,0 +1,198 @@ +# # frozen_string_literal: true + +# # Copyright The OpenTelemetry Authors +# # +# # SPDX-License-Identifier: Apache-2.0 + +# require 'test_helper' + +# require_relative '../../../../../lib/opentelemetry/instrumentation/http' +# require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/stable/client' + +# describe OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Client do +# let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } +# let(:exporter) { EXPORTER } +# let(:span) { exporter.finished_spans.first } +# let(:config) do +# { +# span_name_formatter: span_name_formatter +# } +# end +# let(:span_name_formatter) { nil } + +# ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http' + +# before do +# exporter.reset +# @orig_propagation = OpenTelemetry.propagation +# propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator +# OpenTelemetry.propagation = propagator +# # simulate a fresh install: +# instrumentation.instance_variable_set(:@installed, false) +# instrumentation.install(config) +# stub_request(:get, 'http://example.com/success').to_return(status: 200) +# stub_request(:get, 'http://example.com/success?hello=there').to_return(status: 200) +# stub_request(:post, 'http://example.com/failure').to_return(status: 500) +# stub_request(:get, 'https://example.com/timeout').to_timeout +# end + +# after do +# # Force re-install of instrumentation +# instrumentation.instance_variable_set(:@installed, false) + +# OpenTelemetry.propagation = @orig_propagation +# end + +# describe '#perform' do +# it 'traces a simple request' do +# HTTP.get('http://example.com/success') + +# _(exporter.finished_spans.size).must_equal(1) +# _(span.name).must_equal 'HTTP GET' +# _(span.attributes['http.request.method']).must_equal 'GET' +# _(span.attributes['url.scheme']).must_equal 'http' +# _(span.attributes['http.response.status_code']).must_equal 200 +# _(span.attributes['url.path']).must_equal '/success' +# _(span.attributes['server.address']).must_equal 'example.com' +# _(span.attributes['url.full']).must_equal 'http://example.com' +# _(span.attributes['server.port']).must_equal 80 +# _(span.attributes['url.query']).must_be_nil +# assert_requested( +# :get, +# 'http://example.com/success', +# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } +# ) +# end + +# it 'after request with failure code' do +# HTTP.post('http://example.com/failure') + +# _(exporter.finished_spans.size).must_equal 1 +# _(span.name).must_equal 'HTTP POST' +# _(span.attributes['http.request.method']).must_equal 'POST' +# _(span.attributes['url.scheme']).must_equal 'http' +# _(span.attributes['http.response.status_code']).must_equal 500 +# _(span.attributes['url.path']).must_equal '/failure' +# _(span.attributes['server.address']).must_equal 'example.com' +# _(span.attributes['url.full']).must_equal 'http://example.com' +# _(span.attributes['server.port']).must_equal 80 +# _(span.attributes['url.query']).must_be_nil +# assert_requested( +# :post, +# 'http://example.com/failure', +# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } +# ) +# end + +# it 'after request timeout' do +# expect do +# HTTP.get('https://example.com/timeout') +# end.must_raise HTTP::TimeoutError + +# _(exporter.finished_spans.size).must_equal 1 +# _(span.name).must_equal 'HTTP GET' +# _(span.attributes['http.request.method']).must_equal 'GET' +# _(span.attributes['url.scheme']).must_equal 'https' +# _(span.attributes['http.response.status_code']).must_be_nil +# _(span.attributes['url.path']).must_equal '/timeout' +# _(span.attributes['server.address']).must_equal 'example.com' +# _(span.attributes['url.full']).must_equal 'https://example.com' +# _(span.attributes['server.port']).must_equal 443 +# _(span.attributes['url.query']).must_be_nil +# _(span.status.code).must_equal( +# OpenTelemetry::Trace::Status::ERROR +# ) +# _(span.status.description).must_equal( +# 'Unhandled exception of type: HTTP::TimeoutError' +# ) +# assert_requested( +# :get, +# 'https://example.com/timeout', +# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } +# ) +# end + +# it 'merges http client attributes' do +# OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do +# HTTP.get('http://example.com/success?hello=there') +# end + +# _(exporter.finished_spans.size).must_equal 1 +# _(span.name).must_equal 'HTTP GET' +# _(span.attributes['http.request.method']).must_equal 'GET' +# _(span.attributes['url.scheme']).must_equal 'http' +# _(span.attributes['http.response.status_code']).must_equal 200 +# _(span.attributes['url.path']).must_equal '/success' +# _(span.attributes['server.address']).must_equal 'example.com' +# _(span.attributes['url.full']).must_equal 'http://example.com' +# _(span.attributes['server.port']).must_equal 80 +# _(span.attributes['url.query']).must_equal 'hello=there' +# assert_requested( +# :get, +# 'http://example.com/success?hello=there', +# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } +# ) +# end + +# describe 'when span_name_formatter specified' do +# let(:span_name_formatter) do +# # demonstrate simple addition of path and string to span name: +# lambda { |request_method, request_path| +# "HTTP #{request_method} #{request_path} miniswan" +# } +# end + +# it 'enriches the span' do +# OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do +# HTTP.get('http://example.com/success') +# end + +# _(exporter.finished_spans.size).must_equal 1 +# _(span.name).must_equal 'HTTP GET /success miniswan' +# _(span.attributes['http.request.method']).must_equal 'GET' +# _(span.attributes['url.scheme']).must_equal 'http' +# _(span.attributes['http.response.status_code']).must_equal 200 +# _(span.attributes['url.path']).must_equal '/success' +# _(span.attributes['server.address']).must_equal 'example.com' +# _(span.attributes['url.full']).must_equal 'http://example.com' +# _(span.attributes['server.port']).must_equal 80 +# _(span.attributes['url.query']).must_be_nil +# assert_requested( +# :get, +# 'http://example.com/success', +# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } +# ) +# end +# end +# describe 'when span_formatter specified and it errors' do +# let(:span_name_formatter) do +# # demonstrate simple addition of path and string to span name: +# lambda { |_request_method, _request_path| +# raise 'Something Bad' +# } +# end + +# it 'provides a sane default' do +# OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do +# HTTP.get('http://example.com/success') +# end + +# _(exporter.finished_spans.size).must_equal 1 +# _(span.name).must_equal 'HTTP GET' +# _(span.attributes['http.request.method']).must_equal 'GET' +# _(span.attributes['url.scheme']).must_equal 'http' +# _(span.attributes['http.response.status_code']).must_equal 200 +# _(span.attributes['url.path']).must_equal '/success' +# _(span.attributes['server.address']).must_equal 'example.com' +# _(span.attributes['url.full']).must_equal 'http://example.com' +# _(span.attributes['server.port']).must_equal 80 +# _(span.attributes['url.query']).must_be_nil +# assert_requested( +# :get, +# 'http://example.com/success', +# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } +# ) +# end +# end +# end +# end diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/stable/connection_test.rb new file mode 100644 index 0000000000..12f8644149 --- /dev/null +++ b/instrumentation/http/test/instrumentation/http/patches/stable/connection_test.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +require_relative '../../../../../lib/opentelemetry/instrumentation/http' +require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/stable/connection' + +describe OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Connection do + let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } + let(:exporter) { EXPORTER } + let(:span) { exporter.finished_spans.first } + + before do + exporter.reset + instrumentation.install({}) + end + + # Force re-install of instrumentation + after do + instrumentation.instance_variable_set(:@installed, false) + end + + describe '#connect' do + it 'emits span on connect' do + WebMock.allow_net_connect! + TCPServer.open('localhost', 0) do |server| + Thread.start { server.accept } + port = server.addr[1] + + assert_raises(HTTP::TimeoutError) do + HTTP.timeout(connect: 0.1, write: 0.1, read: 0.1).get("http://localhost:#{port}/example") + end + end + + _(exporter.finished_spans.size).must_equal(2) + _(span.name).must_equal 'HTTP CONNECT' + _(span.attributes['server.address']).must_equal('localhost') + _(span.attributes['server.port']).wont_be_nil + ensure + WebMock.disable_net_connect! + end + end +end From 0cbb1c4c511ba192035c861873e0cc01acf57573 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Thu, 22 May 2025 16:13:35 -0700 Subject: [PATCH 02/11] feat: semconv testing --- instrumentation/http/Appraisals | 19 +- .../instrumentation/http/instrumentation.rb | 2 +- .../http/instrumentation_test.rb | 2 + .../http/patches/dup/client_test.rb | 8 +- .../http/patches/dup/connection_test.rb | 8 +- .../http/patches/old/client_test.rb | 2 + .../old/{connection_test.rb => connection.rb} | 2 + .../http/patches/stable/client_test.rb | 397 +++++++++--------- .../{connection_test.rb => connection.rb} | 4 + 9 files changed, 237 insertions(+), 207 deletions(-) rename instrumentation/http/test/instrumentation/http/patches/old/{connection_test.rb => connection.rb} (96%) rename instrumentation/http/test/instrumentation/http/patches/stable/{connection_test.rb => connection.rb} (89%) diff --git a/instrumentation/http/Appraisals b/instrumentation/http/Appraisals index 5a6c74f7a4..53ba82b2a9 100644 --- a/instrumentation/http/Appraisals +++ b/instrumentation/http/Appraisals @@ -4,10 +4,19 @@ # # SPDX-License-Identifier: Apache-2.0 -appraise 'http-4.4' do - gem 'http', '~> 4.4.0' -end +# To faclitate HTTP semantic convention stability migration, we are using +# appraisal to test the different semantic convention modes along with different +# HTTP gem versions. For more information on the semantic convention modes, see: +# https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/ + +semconv_stability = %w[dup stable old] + +semconv_stability.each do |mode| + appraise "http-4.4 #{mode}" do + gem 'http', '~> 4.4.0' + end -appraise 'http-3.3.0' do - gem 'http', '~> 3.3.0' + appraise "http-3.3 #{mode}" do + gem 'http', '~> 3.3.0' + end end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb index 84326684cd..b5c86874e7 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb @@ -64,4 +64,4 @@ def require_dependencies_stable end end end -end \ No newline at end of file +end diff --git a/instrumentation/http/test/instrumentation/http/instrumentation_test.rb b/instrumentation/http/test/instrumentation/http/instrumentation_test.rb index 302ac483d4..ef582b9657 100644 --- a/instrumentation/http/test/instrumentation/http/instrumentation_test.rb +++ b/instrumentation/http/test/instrumentation/http/instrumentation_test.rb @@ -9,6 +9,8 @@ require_relative '../../../lib/opentelemetry/instrumentation/http' describe OpenTelemetry::Instrumentation::HTTP do + before { skip unless ENV['BUNDLE_GEMFILE'].include?('old') } + let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } it 'has #name' do diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb index 2f555b3e92..1488295c10 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb @@ -20,9 +20,10 @@ end let(:span_name_formatter) { nil } - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' - before do + skip unless ENV['BUNDLE_GEMFILE'].include?('dup') + + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' exporter.reset @orig_propagation = OpenTelemetry.propagation propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator @@ -37,6 +38,7 @@ end after do + ENV.delete('OTEL_SEMCONV_STABILITY_OPT_IN') # Force re-install of instrumentation instrumentation.instance_variable_set(:@installed, false) OpenTelemetry.propagation = @orig_propagation @@ -47,6 +49,7 @@ HTTP.get('http://example.com/success') _(exporter.finished_spans.size).must_equal(1) _(span.name).must_equal 'HTTP GET' + # Old semantic conventions _(span.attributes['http.method']).must_equal 'GET' _(span.attributes['http.scheme']).must_equal 'http' @@ -54,6 +57,7 @@ _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 + # Stable semantic conventions _(span.attributes['http.request.method']).must_equal 'GET' _(span.attributes['url.scheme']).must_equal 'http' diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb index 7eea34df6d..7b3c7a4f33 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb @@ -15,12 +15,16 @@ let(:span) { exporter.finished_spans.first } before do + skip unless ENV['BUNDLE_GEMFILE'].include?('dup') + + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' exporter.reset instrumentation.install({}) end # Force re-install of instrumentation after do + ENV.delete('OTEL_SEMCONV_STABILITY_OPT_IN') instrumentation.instance_variable_set(:@installed, false) end @@ -38,10 +42,12 @@ _(exporter.finished_spans.size).must_equal(2) _(span.name).must_equal 'HTTP CONNECT' + # Old semantic conventions _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).wont_be_nil - # New semantic conventions + + # Stable semantic conventions _(span.attributes['server.address']).must_equal('localhost') _(span.attributes['server.port']).wont_be_nil ensure diff --git a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb index d1baaabc74..6579dc8b5d 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb @@ -21,6 +21,8 @@ let(:span_name_formatter) { nil } before do + skip unless ENV['BUNDLE_GEMFILE'].include?('old') + exporter.reset @orig_propagation = OpenTelemetry.propagation propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator diff --git a/instrumentation/http/test/instrumentation/http/patches/old/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb similarity index 96% rename from instrumentation/http/test/instrumentation/http/patches/old/connection_test.rb rename to instrumentation/http/test/instrumentation/http/patches/old/connection.rb index a94cd16c8c..89ed18b02f 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb @@ -15,6 +15,8 @@ let(:span) { exporter.finished_spans.first } before do + skip unless ENV['BUNDLE_GEMFILE'].include?('old') + exporter.reset instrumentation.install({}) end diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb index f7d152d98e..337b14e7b1 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb @@ -1,198 +1,199 @@ -# # frozen_string_literal: true - -# # Copyright The OpenTelemetry Authors -# # -# # SPDX-License-Identifier: Apache-2.0 - -# require 'test_helper' - -# require_relative '../../../../../lib/opentelemetry/instrumentation/http' -# require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/stable/client' - -# describe OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Client do -# let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } -# let(:exporter) { EXPORTER } -# let(:span) { exporter.finished_spans.first } -# let(:config) do -# { -# span_name_formatter: span_name_formatter -# } -# end -# let(:span_name_formatter) { nil } - -# ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http' - -# before do -# exporter.reset -# @orig_propagation = OpenTelemetry.propagation -# propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator -# OpenTelemetry.propagation = propagator -# # simulate a fresh install: -# instrumentation.instance_variable_set(:@installed, false) -# instrumentation.install(config) -# stub_request(:get, 'http://example.com/success').to_return(status: 200) -# stub_request(:get, 'http://example.com/success?hello=there').to_return(status: 200) -# stub_request(:post, 'http://example.com/failure').to_return(status: 500) -# stub_request(:get, 'https://example.com/timeout').to_timeout -# end - -# after do -# # Force re-install of instrumentation -# instrumentation.instance_variable_set(:@installed, false) - -# OpenTelemetry.propagation = @orig_propagation -# end - -# describe '#perform' do -# it 'traces a simple request' do -# HTTP.get('http://example.com/success') - -# _(exporter.finished_spans.size).must_equal(1) -# _(span.name).must_equal 'HTTP GET' -# _(span.attributes['http.request.method']).must_equal 'GET' -# _(span.attributes['url.scheme']).must_equal 'http' -# _(span.attributes['http.response.status_code']).must_equal 200 -# _(span.attributes['url.path']).must_equal '/success' -# _(span.attributes['server.address']).must_equal 'example.com' -# _(span.attributes['url.full']).must_equal 'http://example.com' -# _(span.attributes['server.port']).must_equal 80 -# _(span.attributes['url.query']).must_be_nil -# assert_requested( -# :get, -# 'http://example.com/success', -# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } -# ) -# end - -# it 'after request with failure code' do -# HTTP.post('http://example.com/failure') - -# _(exporter.finished_spans.size).must_equal 1 -# _(span.name).must_equal 'HTTP POST' -# _(span.attributes['http.request.method']).must_equal 'POST' -# _(span.attributes['url.scheme']).must_equal 'http' -# _(span.attributes['http.response.status_code']).must_equal 500 -# _(span.attributes['url.path']).must_equal '/failure' -# _(span.attributes['server.address']).must_equal 'example.com' -# _(span.attributes['url.full']).must_equal 'http://example.com' -# _(span.attributes['server.port']).must_equal 80 -# _(span.attributes['url.query']).must_be_nil -# assert_requested( -# :post, -# 'http://example.com/failure', -# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } -# ) -# end - -# it 'after request timeout' do -# expect do -# HTTP.get('https://example.com/timeout') -# end.must_raise HTTP::TimeoutError - -# _(exporter.finished_spans.size).must_equal 1 -# _(span.name).must_equal 'HTTP GET' -# _(span.attributes['http.request.method']).must_equal 'GET' -# _(span.attributes['url.scheme']).must_equal 'https' -# _(span.attributes['http.response.status_code']).must_be_nil -# _(span.attributes['url.path']).must_equal '/timeout' -# _(span.attributes['server.address']).must_equal 'example.com' -# _(span.attributes['url.full']).must_equal 'https://example.com' -# _(span.attributes['server.port']).must_equal 443 -# _(span.attributes['url.query']).must_be_nil -# _(span.status.code).must_equal( -# OpenTelemetry::Trace::Status::ERROR -# ) -# _(span.status.description).must_equal( -# 'Unhandled exception of type: HTTP::TimeoutError' -# ) -# assert_requested( -# :get, -# 'https://example.com/timeout', -# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } -# ) -# end - -# it 'merges http client attributes' do -# OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do -# HTTP.get('http://example.com/success?hello=there') -# end - -# _(exporter.finished_spans.size).must_equal 1 -# _(span.name).must_equal 'HTTP GET' -# _(span.attributes['http.request.method']).must_equal 'GET' -# _(span.attributes['url.scheme']).must_equal 'http' -# _(span.attributes['http.response.status_code']).must_equal 200 -# _(span.attributes['url.path']).must_equal '/success' -# _(span.attributes['server.address']).must_equal 'example.com' -# _(span.attributes['url.full']).must_equal 'http://example.com' -# _(span.attributes['server.port']).must_equal 80 -# _(span.attributes['url.query']).must_equal 'hello=there' -# assert_requested( -# :get, -# 'http://example.com/success?hello=there', -# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } -# ) -# end - -# describe 'when span_name_formatter specified' do -# let(:span_name_formatter) do -# # demonstrate simple addition of path and string to span name: -# lambda { |request_method, request_path| -# "HTTP #{request_method} #{request_path} miniswan" -# } -# end - -# it 'enriches the span' do -# OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do -# HTTP.get('http://example.com/success') -# end - -# _(exporter.finished_spans.size).must_equal 1 -# _(span.name).must_equal 'HTTP GET /success miniswan' -# _(span.attributes['http.request.method']).must_equal 'GET' -# _(span.attributes['url.scheme']).must_equal 'http' -# _(span.attributes['http.response.status_code']).must_equal 200 -# _(span.attributes['url.path']).must_equal '/success' -# _(span.attributes['server.address']).must_equal 'example.com' -# _(span.attributes['url.full']).must_equal 'http://example.com' -# _(span.attributes['server.port']).must_equal 80 -# _(span.attributes['url.query']).must_be_nil -# assert_requested( -# :get, -# 'http://example.com/success', -# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } -# ) -# end -# end -# describe 'when span_formatter specified and it errors' do -# let(:span_name_formatter) do -# # demonstrate simple addition of path and string to span name: -# lambda { |_request_method, _request_path| -# raise 'Something Bad' -# } -# end - -# it 'provides a sane default' do -# OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do -# HTTP.get('http://example.com/success') -# end - -# _(exporter.finished_spans.size).must_equal 1 -# _(span.name).must_equal 'HTTP GET' -# _(span.attributes['http.request.method']).must_equal 'GET' -# _(span.attributes['url.scheme']).must_equal 'http' -# _(span.attributes['http.response.status_code']).must_equal 200 -# _(span.attributes['url.path']).must_equal '/success' -# _(span.attributes['server.address']).must_equal 'example.com' -# _(span.attributes['url.full']).must_equal 'http://example.com' -# _(span.attributes['server.port']).must_equal 80 -# _(span.attributes['url.query']).must_be_nil -# assert_requested( -# :get, -# 'http://example.com/success', -# headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } -# ) -# end -# end -# end -# end +# frozen_string_literal: true + +# Copyright The OpenTelemetry Authors +# +# SPDX-License-Identifier: Apache-2.0 + +require 'test_helper' + +require_relative '../../../../../lib/opentelemetry/instrumentation/http' +require_relative '../../../../../lib/opentelemetry/instrumentation/http/patches/stable/client' + +describe OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Client do + let(:instrumentation) { OpenTelemetry::Instrumentation::HTTP::Instrumentation.instance } + let(:exporter) { EXPORTER } + let(:span) { exporter.finished_spans.first } + let(:config) do + { + span_name_formatter: span_name_formatter + } + end + let(:span_name_formatter) { nil } + + before do + skip unless ENV['BUNDLE_GEMFILE'].include?('stable') + + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http' + exporter.reset + @orig_propagation = OpenTelemetry.propagation + propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator + OpenTelemetry.propagation = propagator + # simulate a fresh install: + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(config) + stub_request(:get, 'http://example.com/success').to_return(status: 200) + stub_request(:get, 'http://example.com/success?hello=there').to_return(status: 200) + stub_request(:post, 'http://example.com/failure').to_return(status: 500) + stub_request(:get, 'https://example.com/timeout').to_timeout + end + + after do + ENV.delete('OTEL_SEMCONV_STABILITY_OPT_IN') + # Force re-install of instrumentation + instrumentation.instance_variable_set(:@installed, false) + + OpenTelemetry.propagation = @orig_propagation + end + + describe '#perform' do + it 'traces a simple request' do + HTTP.get('http://example.com/success') + _(exporter.finished_spans.size).must_equal(1) + _(span.name).must_equal 'HTTP GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + assert_requested( + :get, + 'http://example.com/success', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + it 'after request with failure code' do + HTTP.post('http://example.com/failure') + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP POST' + _(span.attributes['http.request.method']).must_equal 'POST' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 500 + _(span.attributes['url.path']).must_equal '/failure' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + assert_requested( + :post, + 'http://example.com/failure', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + it 'after request timeout' do + expect do + HTTP.get('https://example.com/timeout') + end.must_raise HTTP::TimeoutError + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'https' + _(span.attributes['http.response.status_code']).must_be_nil + _(span.attributes['url.path']).must_equal '/timeout' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'https://example.com' + _(span.attributes['server.port']).must_equal 443 + _(span.attributes['url.query']).must_be_nil + _(span.status.code).must_equal( + OpenTelemetry::Trace::Status::ERROR + ) + _(span.status.description).must_equal( + 'Unhandled exception of type: HTTP::TimeoutError' + ) + assert_requested( + :get, + 'https://example.com/timeout', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + it 'merges http client attributes' do + OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do + HTTP.get('http://example.com/success?hello=there') + end + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_equal 'hello=there' + assert_requested( + :get, + 'http://example.com/success?hello=there', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + + describe 'when span_name_formatter specified' do + let(:span_name_formatter) do + # demonstrate simple addition of path and string to span name: + lambda { |request_method, request_path| + "HTTP #{request_method} #{request_path} miniswan" + } + end + + it 'enriches the span' do + OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do + HTTP.get('http://example.com/success') + end + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET /success miniswan' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + assert_requested( + :get, + 'http://example.com/success', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + end + describe 'when span_formatter specified and it errors' do + let(:span_name_formatter) do + # demonstrate simple addition of path and string to span name: + lambda { |_request_method, _request_path| + raise 'Something Bad' + } + end + + it 'provides a sane default' do + OpenTelemetry::Common::HTTP::ClientContext.with_attributes('peer.service' => 'foo') do + HTTP.get('http://example.com/success') + end + + _(exporter.finished_spans.size).must_equal 1 + _(span.name).must_equal 'HTTP GET' + _(span.attributes['http.request.method']).must_equal 'GET' + _(span.attributes['url.scheme']).must_equal 'http' + _(span.attributes['http.response.status_code']).must_equal 200 + _(span.attributes['url.path']).must_equal '/success' + _(span.attributes['server.address']).must_equal 'example.com' + _(span.attributes['url.full']).must_equal 'http://example.com' + _(span.attributes['server.port']).must_equal 80 + _(span.attributes['url.query']).must_be_nil + assert_requested( + :get, + 'http://example.com/success', + headers: { 'Traceparent' => "00-#{span.hex_trace_id}-#{span.hex_span_id}-01" } + ) + end + end + end +end diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb similarity index 89% rename from instrumentation/http/test/instrumentation/http/patches/stable/connection_test.rb rename to instrumentation/http/test/instrumentation/http/patches/stable/connection.rb index 12f8644149..1f6285bb3d 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb @@ -15,12 +15,16 @@ let(:span) { exporter.finished_spans.first } before do + skip unless ENV['BUNDLE_GEMFILE'].include?('stable') + + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http' exporter.reset instrumentation.install({}) end # Force re-install of instrumentation after do + ENV.delete('OTEL_SEMCONV_STABILITY_OPT_IN') instrumentation.instance_variable_set(:@installed, false) end From e6e970c264a73b86bf70942d81b89b1a6bffb342 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Tue, 27 May 2025 09:16:48 -0700 Subject: [PATCH 03/11] Clean up appraisal file --- instrumentation/http/Appraisals | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/http/Appraisals b/instrumentation/http/Appraisals index 53ba82b2a9..3e908a481d 100644 --- a/instrumentation/http/Appraisals +++ b/instrumentation/http/Appraisals @@ -12,11 +12,11 @@ semconv_stability = %w[dup stable old] semconv_stability.each do |mode| - appraise "http-4.4 #{mode}" do + appraise "http-4.4.0-#{mode}" do gem 'http', '~> 4.4.0' end - appraise "http-3.3 #{mode}" do + appraise "http-3.3.0-#{mode}" do gem 'http', '~> 3.3.0' end end From 7e5f4ff4bee1d78cd924e95dc290e4510d13c481 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Tue, 27 May 2025 09:32:41 -0700 Subject: [PATCH 04/11] Appease Rubocop --- .../opentelemetry/instrumentation/http/patches/dup/client.rb | 4 ++-- .../opentelemetry/instrumentation/http/patches/old/client.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb index d82776a3b1..1df4e43be9 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/dup/client.rb @@ -57,8 +57,8 @@ def annotate_span_with_response!(span, response) return unless response&.status status_code = response.status.to_i - span.set_attribute('http.status_code', status_code) #old semconv - span.set_attribute('http.response.status_code', status_code) #stable semconv + span.set_attribute('http.status_code', status_code) # old semconv + span.set_attribute('http.response.status_code', status_code) # stable semconv span.status = OpenTelemetry::Trace::Status.error unless HTTP_STATUS_SUCCESS_RANGE.cover?(status_code) end diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb index aa47d12744..356a7caee9 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/patches/old/client.rb @@ -9,7 +9,7 @@ module Instrumentation module HTTP module Patches # Module using old HTTP semantic conventions - module Old + module Old # Module to prepend to HTTP::Client for instrumentation module Client # Constant for the HTTP status range From 3f3ff4e4ab286dd62dc310d7bdfa5562aee72b78 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Wed, 28 May 2025 12:59:28 -0700 Subject: [PATCH 05/11] Add README and consider database migration env vars --- instrumentation/http/README.md | 16 ++++++++++++++++ .../instrumentation/http/instrumentation.rb | 8 +++++--- .../http/patches/dup/client_test.rb | 2 +- .../http/patches/dup/connection_test.rb | 2 +- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/instrumentation/http/README.md b/instrumentation/http/README.md index 91d7fe8d99..e08080a7b5 100644 --- a/instrumentation/http/README.md +++ b/instrumentation/http/README.md @@ -64,3 +64,19 @@ The `opentelemetry-instrumentation-http` gem is distributed under the Apache 2.0 [community-meetings]: https://github.com/open-telemetry/community#community-meetings [slack-channel]: https://cloud-native.slack.com/archives/C01NWKKMKMY [discussions-url]: https://github.com/open-telemetry/opentelemetry-ruby/discussions + +## HTTP semantic convention stability + +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. + +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. + +When setting the value for `OTEL_SEMCONV_STABILITY_OPT_IN`, you can specify which conventions you wish to adopt: + +- `http` - Emits the stable HTTP and networking conventions and ceases emitting the old conventions previously emitted by the instrumentation. +- `http/dup` - Emits both the old and stable HTTP and networking conventions, enabling a phased rollout of the stable semantic conventions. +- Default behavior (in the absence of either value) is to continue emitting the old HTTP and networking conventions the instrumentation previously emitted. + +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. + +For additional information on migration, please refer to our [documentation](https://opentelemetry.io/docs/specs/semconv/non-normative/http-migration/). diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb index b5c86874e7..aa1a7d0da5 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb @@ -22,10 +22,12 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base option :span_name_formatter, default: nil, validate: :callable def determine_semconv - case ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil) - when 'http/dup' + stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil) + values = stability_opt_in&.split(',') + + if values.include?('http/dup') 'dup' - when 'http' + elsif values.include?('http') 'stable' else 'old' diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb index 1488295c10..5150af9f94 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb @@ -23,7 +23,7 @@ before do skip unless ENV['BUNDLE_GEMFILE'].include?('dup') - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' exporter.reset @orig_propagation = OpenTelemetry.propagation propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb index 7b3c7a4f33..2766b994ac 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb @@ -17,7 +17,7 @@ before do skip unless ENV['BUNDLE_GEMFILE'].include?('dup') - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' exporter.reset instrumentation.install({}) end From f1c97016df3b9977e60bea5ec59ba91d74974930 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Wed, 28 May 2025 13:07:05 -0700 Subject: [PATCH 06/11] safe nav stability_opt_in --- .../lib/opentelemetry/instrumentation/http/instrumentation.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb index aa1a7d0da5..1329e8b1e3 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb @@ -25,9 +25,9 @@ def determine_semconv stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil) values = stability_opt_in&.split(',') - if values.include?('http/dup') + if values&.include?('http/dup') 'dup' - elsif values.include?('http') + elsif values&.include?('http') 'stable' else 'old' From 62ce61e7f6db4702b0d3739f6e72e15bc22e5721 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Thu, 29 May 2025 08:11:58 -0700 Subject: [PATCH 07/11] Add tests for environment variable --- .../instrumentation/http/instrumentation.rb | 8 +++--- .../http/patches/dup/client_test.rb | 25 ++++++++++++++++++- .../http/patches/dup/connection_test.rb | 11 +++++++- .../http/patches/old/client_test.rb | 12 +++++++++ .../http/patches/old/connection.rb | 12 +++++++++ .../http/patches/stable/client_test.rb | 12 +++++++++ .../http/patches/stable/connection.rb | 9 +++++++ 7 files changed, 83 insertions(+), 6 deletions(-) diff --git a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb index 1329e8b1e3..a7d228cfd3 100644 --- a/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb +++ b/instrumentation/http/lib/opentelemetry/instrumentation/http/instrumentation.rb @@ -22,12 +22,12 @@ class Instrumentation < OpenTelemetry::Instrumentation::Base option :span_name_formatter, default: nil, validate: :callable def determine_semconv - stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', nil) - values = stability_opt_in&.split(',') + stability_opt_in = ENV.fetch('OTEL_SEMCONV_STABILITY_OPT_IN', '') + values = stability_opt_in.split(',').map(&:strip) - if values&.include?('http/dup') + if values.include?('http/dup') 'dup' - elsif values&.include?('http') + elsif values.include?('http') 'stable' else 'old' diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb index 5150af9f94..6b351217e2 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb @@ -23,7 +23,7 @@ before do skip unless ENV['BUNDLE_GEMFILE'].include?('dup') - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' exporter.reset @orig_propagation = OpenTelemetry.propagation propagator = OpenTelemetry::Trace::Propagation::TraceContext.text_map_propagator @@ -44,6 +44,29 @@ OpenTelemetry.propagation = @orig_propagation end + describe 'installation' do + it 'applies the correct patch when stability options include only http/dup and database' do + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' + + # simulate a fresh install: + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(config) + + _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Client + end + + it 'applies the http/dup patch and excludes the Stable patch when both http and http/dup are present' do + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http, http/dup' + + # simulate a fresh install: + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(config) + + _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Client + _(HTTP::Client.ancestors).wont_include OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Client + end + end + describe '#perform' do it 'traces a simple request' do HTTP.get('http://example.com/success') diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb index 2766b994ac..56df0d569c 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb @@ -17,7 +17,7 @@ before do skip unless ENV['BUNDLE_GEMFILE'].include?('dup') - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup' exporter.reset instrumentation.install({}) end @@ -28,6 +28,15 @@ instrumentation.instance_variable_set(:@installed, false) end + describe 'installation' do + it 'installs the patch when env var has multiple configs' do + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' + instrumentation.install({}) # simulate a fresh install: + + _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection + end + end + describe '#connect' do it 'emits span on connect' do WebMock.allow_net_connect! diff --git a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb index 6579dc8b5d..67ea9f4c27 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb @@ -42,6 +42,18 @@ OpenTelemetry.propagation = @orig_propagation end + describe 'installation' do + it 'applies the correct patch when stability options do not include HTTP stability modes' do + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'database' + + # simulate a fresh install: + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(config) + + _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Old::Client + end + end + describe '#perform' do it 'traces a simple request' do HTTP.get('http://example.com/success') diff --git a/instrumentation/http/test/instrumentation/http/patches/old/connection.rb b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb index 89ed18b02f..a8db840264 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/connection.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb @@ -24,6 +24,18 @@ # Force re-install of instrumentation after { instrumentation.instance_variable_set(:@installed, false) } + describe 'installation' do + it 'applies the correct patch when stability options do not include HTTP stability modes' do + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'database' + + # simulate a fresh install: + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(config) + + _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Old::Connection + end + end + describe '#connect' do it 'emits span on connect' do WebMock.allow_net_connect! diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb index 337b14e7b1..192b991ba7 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb @@ -45,6 +45,18 @@ OpenTelemetry.propagation = @orig_propagation end + describe 'installation' do + it 'applies the correct patch when stability options include only http/dup and database' do + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http, database' + + # simulate a fresh install: + instrumentation.instance_variable_set(:@installed, false) + instrumentation.install(config) + + _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Client + end + end + describe '#perform' do it 'traces a simple request' do HTTP.get('http://example.com/success') diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb index 1f6285bb3d..54192f4a53 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb @@ -28,6 +28,15 @@ instrumentation.instance_variable_set(:@installed, false) end + describe 'installation' do + it 'installs the patch when env var has multiple configs' do + ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' + instrumentation.install({}) # simulate a fresh install: + + _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection + end + end + describe '#connect' do it 'emits span on connect' do WebMock.allow_net_connect! From 3cfcc1e4a9dd27292de23b6c7d0c285cf6a46e6f Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Thu, 29 May 2025 08:32:47 -0700 Subject: [PATCH 08/11] Appease rubocop --- .../http/test/instrumentation/http/patches/stable/connection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb index 54192f4a53..9819a99a28 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb @@ -33,7 +33,7 @@ ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' instrumentation.install({}) # simulate a fresh install: - _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection + _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection end end From c990c28f4a2d12a374aa2b590ffb4714e9f4048d Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Thu, 29 May 2025 08:56:36 -0700 Subject: [PATCH 09/11] Cleanup --- .../test/instrumentation/http/patches/dup/client_test.rb | 4 ---- .../test/instrumentation/http/patches/dup/connection_test.rb | 4 +--- .../test/instrumentation/http/patches/old/client_test.rb | 1 - .../http/test/instrumentation/http/patches/old/connection.rb | 5 +---- .../test/instrumentation/http/patches/stable/client_test.rb | 1 - .../test/instrumentation/http/patches/stable/connection.rb | 2 +- 6 files changed, 3 insertions(+), 14 deletions(-) diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb index 6b351217e2..31f9fe0366 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb @@ -47,7 +47,6 @@ describe 'installation' do it 'applies the correct patch when stability options include only http/dup and database' do ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' - # simulate a fresh install: instrumentation.instance_variable_set(:@installed, false) instrumentation.install(config) @@ -57,7 +56,6 @@ it 'applies the http/dup patch and excludes the Stable patch when both http and http/dup are present' do ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http, http/dup' - # simulate a fresh install: instrumentation.instance_variable_set(:@installed, false) instrumentation.install(config) @@ -72,7 +70,6 @@ HTTP.get('http://example.com/success') _(exporter.finished_spans.size).must_equal(1) _(span.name).must_equal 'HTTP GET' - # Old semantic conventions _(span.attributes['http.method']).must_equal 'GET' _(span.attributes['http.scheme']).must_equal 'http' @@ -80,7 +77,6 @@ _(span.attributes['http.target']).must_equal '/success' _(span.attributes['net.peer.name']).must_equal 'example.com' _(span.attributes['net.peer.port']).must_equal 80 - # Stable semantic conventions _(span.attributes['http.request.method']).must_equal 'GET' _(span.attributes['url.scheme']).must_equal 'http' diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb index 56df0d569c..accafb367b 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb @@ -31,7 +31,7 @@ describe 'installation' do it 'installs the patch when env var has multiple configs' do ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' - instrumentation.install({}) # simulate a fresh install: + instrumentation.install({}) # simulate a fresh install _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection end @@ -51,11 +51,9 @@ _(exporter.finished_spans.size).must_equal(2) _(span.name).must_equal 'HTTP CONNECT' - # Old semantic conventions _(span.attributes['net.peer.name']).must_equal('localhost') _(span.attributes['net.peer.port']).wont_be_nil - # Stable semantic conventions _(span.attributes['server.address']).must_equal('localhost') _(span.attributes['server.port']).wont_be_nil diff --git a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb index 67ea9f4c27..61429bb695 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb @@ -45,7 +45,6 @@ describe 'installation' do it 'applies the correct patch when stability options do not include HTTP stability modes' do ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'database' - # simulate a fresh install: instrumentation.instance_variable_set(:@installed, false) instrumentation.install(config) diff --git a/instrumentation/http/test/instrumentation/http/patches/old/connection.rb b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb index a8db840264..724438912f 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/connection.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb @@ -27,10 +27,7 @@ describe 'installation' do it 'applies the correct patch when stability options do not include HTTP stability modes' do ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'database' - - # simulate a fresh install: - instrumentation.instance_variable_set(:@installed, false) - instrumentation.install(config) + instrumentation.install({}) # simulate a fresh install _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Old::Connection end diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb index 192b991ba7..e30d802992 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb @@ -48,7 +48,6 @@ describe 'installation' do it 'applies the correct patch when stability options include only http/dup and database' do ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http, database' - # simulate a fresh install: instrumentation.instance_variable_set(:@installed, false) instrumentation.install(config) diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb index 9819a99a28..6824812a03 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb @@ -31,7 +31,7 @@ describe 'installation' do it 'installs the patch when env var has multiple configs' do ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' - instrumentation.install({}) # simulate a fresh install: + instrumentation.install({}) # simulate a fresh install _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection end From b4f01bbc4706a769f84854eaa619e631eff0c792 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Thu, 29 May 2025 12:50:57 -0700 Subject: [PATCH 10/11] Test refactor --- .../http/instrumentation_test.rb | 26 +++++++++++++++++++ .../http/patches/dup/client_test.rb | 21 --------------- .../http/patches/dup/connection_test.rb | 9 ------- .../http/patches/old/client_test.rb | 11 -------- .../http/patches/old/connection.rb | 9 ------- .../http/patches/stable/client_test.rb | 11 -------- .../http/patches/stable/connection.rb | 9 ------- 7 files changed, 26 insertions(+), 70 deletions(-) diff --git a/instrumentation/http/test/instrumentation/http/instrumentation_test.rb b/instrumentation/http/test/instrumentation/http/instrumentation_test.rb index ef582b9657..7a079d912f 100644 --- a/instrumentation/http/test/instrumentation/http/instrumentation_test.rb +++ b/instrumentation/http/test/instrumentation/http/instrumentation_test.rb @@ -38,4 +38,30 @@ _(instrumentation.install({})).must_equal(true) end end + + describe 'determine_semconv' do + it 'returns "dup" when OTEL_SEMCONV_STABILITY_OPT_IN includes other configs' do + OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => 'http/dup, database') do + _(determine_semconv).must_equal('dup') + end + end + + it 'returns "dup" when OTEL_SEMCONV_STABILITY_OPT_IN includes both http/dup and http' do + OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => 'http/dup, http') do + _(determine_semconv).must_equal('dup') + end + end + + it 'returns "stable" when OTEL_SEMCONV_STABILITY_OPT_IN is http' do + OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => 'http') do + _(determine_semconv).must_equal('stable') + end + end + + it 'returns "old" when OTEL_SEMCONV_STABILITY_OPT_IN is empty' do + OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => '') do + _(determine_semconv).must_equal('old') + end + end + end end diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb index 31f9fe0366..ad6916b2ca 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/client_test.rb @@ -44,27 +44,6 @@ OpenTelemetry.propagation = @orig_propagation end - describe 'installation' do - it 'applies the correct patch when stability options include only http/dup and database' do - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' - # simulate a fresh install: - instrumentation.instance_variable_set(:@installed, false) - instrumentation.install(config) - - _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Client - end - - it 'applies the http/dup patch and excludes the Stable patch when both http and http/dup are present' do - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http, http/dup' - # simulate a fresh install: - instrumentation.instance_variable_set(:@installed, false) - instrumentation.install(config) - - _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Client - _(HTTP::Client.ancestors).wont_include OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Client - end - end - describe '#perform' do it 'traces a simple request' do HTTP.get('http://example.com/success') diff --git a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb index accafb367b..9e17123da9 100644 --- a/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/dup/connection_test.rb @@ -28,15 +28,6 @@ instrumentation.instance_variable_set(:@installed, false) end - describe 'installation' do - it 'installs the patch when env var has multiple configs' do - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' - instrumentation.install({}) # simulate a fresh install - - _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection - end - end - describe '#connect' do it 'emits span on connect' do WebMock.allow_net_connect! diff --git a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb index 61429bb695..6579dc8b5d 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/client_test.rb @@ -42,17 +42,6 @@ OpenTelemetry.propagation = @orig_propagation end - describe 'installation' do - it 'applies the correct patch when stability options do not include HTTP stability modes' do - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'database' - # simulate a fresh install: - instrumentation.instance_variable_set(:@installed, false) - instrumentation.install(config) - - _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Old::Client - end - end - describe '#perform' do it 'traces a simple request' do HTTP.get('http://example.com/success') diff --git a/instrumentation/http/test/instrumentation/http/patches/old/connection.rb b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb index 724438912f..89ed18b02f 100644 --- a/instrumentation/http/test/instrumentation/http/patches/old/connection.rb +++ b/instrumentation/http/test/instrumentation/http/patches/old/connection.rb @@ -24,15 +24,6 @@ # Force re-install of instrumentation after { instrumentation.instance_variable_set(:@installed, false) } - describe 'installation' do - it 'applies the correct patch when stability options do not include HTTP stability modes' do - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'database' - instrumentation.install({}) # simulate a fresh install - - _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Old::Connection - end - end - describe '#connect' do it 'emits span on connect' do WebMock.allow_net_connect! diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb index e30d802992..337b14e7b1 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/client_test.rb @@ -45,17 +45,6 @@ OpenTelemetry.propagation = @orig_propagation end - describe 'installation' do - it 'applies the correct patch when stability options include only http/dup and database' do - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http, database' - # simulate a fresh install: - instrumentation.instance_variable_set(:@installed, false) - instrumentation.install(config) - - _(HTTP::Client.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Stable::Client - end - end - describe '#perform' do it 'traces a simple request' do HTTP.get('http://example.com/success') diff --git a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb index 6824812a03..1f6285bb3d 100644 --- a/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb +++ b/instrumentation/http/test/instrumentation/http/patches/stable/connection.rb @@ -28,15 +28,6 @@ instrumentation.instance_variable_set(:@installed, false) end - describe 'installation' do - it 'installs the patch when env var has multiple configs' do - ENV['OTEL_SEMCONV_STABILITY_OPT_IN'] = 'http/dup, database' - instrumentation.install({}) # simulate a fresh install - - _(HTTP::Connection.ancestors).must_include OpenTelemetry::Instrumentation::HTTP::Patches::Dup::Connection - end - end - describe '#connect' do it 'emits span on connect' do WebMock.allow_net_connect! From 4f71d4b46bb8959b2dc4249bc722500d262fe0a0 Mon Sep 17 00:00:00 2001 From: Hannah Ramadan Date: Thu, 29 May 2025 15:13:41 -0700 Subject: [PATCH 11/11] update determine_semconv test --- .../test/instrumentation/http/instrumentation_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/instrumentation/http/test/instrumentation/http/instrumentation_test.rb b/instrumentation/http/test/instrumentation/http/instrumentation_test.rb index 7a079d912f..3bc4ca26cc 100644 --- a/instrumentation/http/test/instrumentation/http/instrumentation_test.rb +++ b/instrumentation/http/test/instrumentation/http/instrumentation_test.rb @@ -42,25 +42,25 @@ describe 'determine_semconv' do it 'returns "dup" when OTEL_SEMCONV_STABILITY_OPT_IN includes other configs' do OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => 'http/dup, database') do - _(determine_semconv).must_equal('dup') + _(instrumentation.determine_semconv).must_equal('dup') end end it 'returns "dup" when OTEL_SEMCONV_STABILITY_OPT_IN includes both http/dup and http' do OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => 'http/dup, http') do - _(determine_semconv).must_equal('dup') + _(instrumentation.determine_semconv).must_equal('dup') end end it 'returns "stable" when OTEL_SEMCONV_STABILITY_OPT_IN is http' do OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => 'http') do - _(determine_semconv).must_equal('stable') + _(instrumentation.determine_semconv).must_equal('stable') end end it 'returns "old" when OTEL_SEMCONV_STABILITY_OPT_IN is empty' do OpenTelemetry::TestHelpers.with_env('OTEL_SEMCONV_STABILITY_OPT_IN' => '') do - _(determine_semconv).must_equal('old') + _(instrumentation.determine_semconv).must_equal('old') end end end