diff --git a/lib/logtail-rack/http_request.rb b/lib/logtail-rack/http_request.rb index 7cc3b95..d0db3a3 100755 --- a/lib/logtail-rack/http_request.rb +++ b/lib/logtail-rack/http_request.rb @@ -1,3 +1,5 @@ +require "json" + require "logtail-rack/util/encoding" module Logtail @@ -26,7 +28,7 @@ def initialize(attributes) @service_name = attributes[:service_name] if @headers - @headers_json = Util::Encoding.force_utf8_encoding(@headers).to_json + @headers_json = ::JSON.generate(Util::Encoding.force_utf8_encoding(@headers)) end end diff --git a/lib/logtail-rack/http_response.rb b/lib/logtail-rack/http_response.rb index 4599012..72c1520 100755 --- a/lib/logtail-rack/http_response.rb +++ b/lib/logtail-rack/http_response.rb @@ -1,3 +1,5 @@ +require "json" + require "logtail-rack/util/encoding" module Logtail @@ -21,7 +23,7 @@ def initialize(attributes) @duration_ms = attributes[:duration_ms] if @headers - @headers_json = Util::Encoding.force_utf8_encoding(@headers).to_json + @headers_json = ::JSON.generate(Util::Encoding.force_utf8_encoding(@headers)) end end diff --git a/spec/logtail-rack/http_request_spec.rb b/spec/logtail-rack/http_request_spec.rb index 354eff0..273c761 100755 --- a/spec/logtail-rack/http_request_spec.rb +++ b/spec/logtail-rack/http_request_spec.rb @@ -3,4 +3,16 @@ require "spec_helper" RSpec.describe Logtail::Integrations::Rack::HTTPRequest do + it "build headers_json when to_json raises, as it does with json 3 and ActiveSupport 8.0 or older" do + # ActiveSupport up to 8.0 encodes a direct #to_json call itself and passes quirks_mode: to JSON.generate, + # which json 3 rejects. JSON.generate calls #to_json with a JSON::State, which ActiveSupport hands to json. + allow_any_instance_of(Hash).to receive(:to_json).and_wrap_original do |to_json, *args| + raise ArgumentError, "unknown keyword: :quirks_mode" unless args.first.is_a?(JSON::State) + to_json.call(*args) + end + + http_request = described_class.new(headers: { "Content_Type" => "text/plain", "Accept" => "*/*" }) + + expect(http_request.headers_json).to eq('{"Content_Type":"text/plain","Accept":"*/*"}') + end end diff --git a/spec/logtail-rack/http_response_spec.rb b/spec/logtail-rack/http_response_spec.rb index c4a5a49..7755644 100755 --- a/spec/logtail-rack/http_response_spec.rb +++ b/spec/logtail-rack/http_response_spec.rb @@ -1,4 +1,16 @@ require "spec_helper" RSpec.describe Logtail::Integrations::Rack::HTTPResponse do + it "build headers_json when to_json raises, as it does with json 3 and ActiveSupport 8.0 or older" do + # ActiveSupport up to 8.0 encodes a direct #to_json call itself and passes quirks_mode: to JSON.generate, + # which json 3 rejects. JSON.generate calls #to_json with a JSON::State, which ActiveSupport hands to json. + allow_any_instance_of(Hash).to receive(:to_json).and_wrap_original do |to_json, *args| + raise ArgumentError, "unknown keyword: :quirks_mode" unless args.first.is_a?(JSON::State) + to_json.call(*args) + end + + http_response = described_class.new(headers: { "content-type" => "text/plain", "content-length" => "5" }, status: 200) + + expect(http_response.headers_json).to eq('{"content-type":"text/plain","content-length":"5"}') + end end