From 05b0489c6006dca8458cbadbb7791b2907365eae Mon Sep 17 00:00:00 2001 From: Lance Erickson Date: Thu, 26 Mar 2026 10:19:01 -0500 Subject: [PATCH 1/2] Fix #613: Support http gem v6.0+ keyword arguments in HTTP instrumentation http gem v6.0 changed HTTP::Client#request from positional args (verb, uri, opts = {}) to keyword args (verb, uri, **opts). Add version detection and separate instrumentation paths for v5 (positional) and v6+ (keyword) to maintain backwards compatibility. Co-Authored-By: Claude Code --- lib/scout_apm/instruments/http.rb | 76 ++++++++++++++++++++++++------ test/unit/instruments/http_test.rb | 7 ++- 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/lib/scout_apm/instruments/http.rb b/lib/scout_apm/instruments/http.rb index b8c6d70e..b6ae02d0 100644 --- a/lib/scout_apm/instruments/http.rb +++ b/lib/scout_apm/instruments/http.rb @@ -24,30 +24,63 @@ def install(prepend:) if prepend ::HTTP::Client.send(:include, ScoutApm::Tracer) - ::HTTP::Client.send(:prepend, HTTPInstrumentationPrepend) + if http_version_at_least?("6.0.0") + ::HTTP::Client.send(:prepend, HTTPInstrumentationPrependV6) + else + ::HTTP::Client.send(:prepend, HTTPInstrumentationPrepend) + end else - ::HTTP::Client.class_eval do - include ScoutApm::Tracer + if http_version_at_least?("6.0.0") + ::HTTP::Client.class_eval do + include ScoutApm::Tracer - def request_with_scout_instruments(verb, uri, opts = {}) - self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do - request_without_scout_instruments(verb, uri, opts) + def request_with_scout_instruments(verb, uri, **opts) + self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do + request_without_scout_instruments(verb, uri, **opts) + end + end + + def request_scout_description(verb, uri) + max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length') + (String(uri).split('?').first)[0..(max_length - 1)] + rescue + "" end - end - def request_scout_description(verb, uri) - max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length') - (String(uri).split('?').first)[0..(max_length - 1)] - rescue - "" + alias request_without_scout_instruments request + alias request request_with_scout_instruments end + else + ::HTTP::Client.class_eval do + include ScoutApm::Tracer + + def request_with_scout_instruments(verb, uri, opts = {}) + self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do + request_without_scout_instruments(verb, uri, opts) + end + end - alias request_without_scout_instruments request - alias request request_with_scout_instruments + def request_scout_description(verb, uri) + max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length') + (String(uri).split('?').first)[0..(max_length - 1)] + rescue + "" + end + + alias request_without_scout_instruments request + alias request request_with_scout_instruments + end end end end end + + private + + def http_version_at_least?(version) + defined?(::HTTP::VERSION) && + Gem::Version.new(::HTTP::VERSION) >= Gem::Version.new(version) + end end module HTTPInstrumentationPrepend @@ -64,5 +97,20 @@ def request_scout_description(verb, uri) "" end end + + module HTTPInstrumentationPrependV6 + def request(verb, uri, **opts) + self.class.instrument("HTTP", verb, :ignore_children => true, :desc => request_scout_description(verb, uri)) do + super(verb, uri, **opts) + end + end + + def request_scout_description(verb, uri) + max_length = ScoutApm::Agent.instance.context.config.value('instrument_http_url_length') + (String(uri).split('?').first)[0..(max_length - 1)] + rescue + "" + end + end end end diff --git a/test/unit/instruments/http_test.rb b/test/unit/instruments/http_test.rb index 6fdc9703..1e50b726 100644 --- a/test/unit/instruments/http_test.rb +++ b/test/unit/instruments/http_test.rb @@ -15,9 +15,14 @@ def setup def test_installs_using_proper_method if @instrument_manager.prepend_for_instrument?(@instance.class) == true - assert ::HTTP::Client.ancestors.include?(ScoutApm::Instruments::HTTPInstrumentationPrepend) + if Gem::Version.new(::HTTP::VERSION) >= Gem::Version.new("6.0.0") + assert ::HTTP::Client.ancestors.include?(ScoutApm::Instruments::HTTPInstrumentationPrependV6) + else + assert ::HTTP::Client.ancestors.include?(ScoutApm::Instruments::HTTPInstrumentationPrepend) + end else assert_equal false, ::HTTP::Client.ancestors.include?(ScoutApm::Instruments::HTTPInstrumentationPrepend) + assert_equal false, ::HTTP::Client.ancestors.include?(ScoutApm::Instruments::HTTPInstrumentationPrependV6) end end end From 8823096fadf4a06aae47b262c2bf464d1e85abf7 Mon Sep 17 00:00:00 2001 From: Lance Erickson Date: Fri, 27 Mar 2026 10:49:04 -0500 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index b25e822c..4b0f4f80 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,5 +1,7 @@ # Pending +- Fix compatibility with `http >= 6.0.0` (#613) + # 6.1.1 - Fix Redis 5 prepend interaction (#611)