Skip to content

Commit 66f6fa8

Browse files
committed
Add service_rates to native transport responses
The `Writer` after_send callback calls `response.service_rates` to update the priority sampler with agent-provided sampling rates. Without this method, every successful flush would raise a `NoMethodError` silently swallowed by the event publisher. - Add `service_rates` to the pure-Ruby `Response` class, which parses the JSON `payload` and extracts `rate_by_service` - Add `service_rates` returning `nil` to `InternalErrorResponse` - Add RBS signatures for both
1 parent ddc9a28 commit 66f6fa8

4 files changed

Lines changed: 86 additions & 0 deletions

File tree

lib/datadog/tracing/transport/native.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
require 'json'
34
require_relative 'trace_formatter'
45
require_relative 'statistics'
56

@@ -131,6 +132,7 @@ def not_found?; false; end
131132
def unsupported?; false; end
132133
def payload; nil; end
133134
def trace_count; 0; end
135+
def service_rates; nil; end
134136

135137
def inspect
136138
"#<#{self.class} error=#{error.inspect}>"

lib/datadog/tracing/transport/native/response.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require 'json'
4+
35
module Datadog
46
module Tracing
57
module Transport
@@ -47,6 +49,21 @@ def not_found?
4749
def unsupported?
4850
@unsupported
4951
end
52+
53+
SERVICE_RATE_KEY = 'rate_by_service'
54+
55+
# Parse the agent's JSON response body and extract the
56+
# +rate_by_service+ map. Returns +nil+ when the payload
57+
# is absent or does not contain sampling rates.
58+
def service_rates
59+
body = payload
60+
return nil if body.nil? || body.empty?
61+
62+
parsed = JSON.parse(body)
63+
parsed[SERVICE_RATE_KEY] if parsed.is_a?(Hash)
64+
rescue JSON::ParserError
65+
nil
66+
end
5067
end
5168
end
5269
end

sig/datadog/tracing/transport/native.rbs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ module Datadog
66

77
def self?.supported?: () -> bool
88

9+
class Response
10+
SERVICE_RATE_KEY: String
11+
12+
def service_rates: () -> (Hash[String, Float] | nil)
13+
end
14+
915
class Transport
1016
include Statistics
1117

@@ -36,6 +42,7 @@ module Datadog
3642
def unsupported?: () -> false
3743
def payload: () -> nil
3844
def trace_count: () -> 0
45+
def service_rates: () -> nil
3946
def inspect: () -> String
4047
end
4148
end

spec/datadog/tracing/transport/native/response_spec.rb

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,63 @@ def make_response(ok:, internal_error: false, server_error: false,
7777
it { expect(response.payload).to be_nil }
7878
end
7979
end
80+
81+
RSpec.describe 'Datadog::Tracing::Transport::Native::Response#service_rates' do
82+
before do
83+
skip_if_libdatadog_not_supported
84+
require 'datadog/tracing/transport/native'
85+
end
86+
87+
let(:response_class) { Datadog::Tracing::Transport::Native::Response }
88+
89+
def make_response(payload:)
90+
resp = response_class.allocate
91+
resp.instance_variable_set(:@ok, true)
92+
resp.instance_variable_set(:@payload, payload)
93+
resp
94+
end
95+
96+
context 'with a valid rate_by_service payload' do
97+
let(:payload) { '{"rate_by_service":{"service:web,env:prod":0.5}}' }
98+
99+
it 'returns the parsed rates hash' do
100+
resp = make_response(payload: payload)
101+
expect(resp.service_rates).to eq({'service:web,env:prod' => 0.5})
102+
end
103+
end
104+
105+
context 'with nil payload' do
106+
it 'returns nil' do
107+
resp = make_response(payload: nil)
108+
expect(resp.service_rates).to be_nil
109+
end
110+
end
111+
112+
context 'with empty payload' do
113+
it 'returns nil' do
114+
resp = make_response(payload: '')
115+
expect(resp.service_rates).to be_nil
116+
end
117+
end
118+
119+
context 'with invalid JSON' do
120+
it 'returns nil' do
121+
resp = make_response(payload: 'not json')
122+
expect(resp.service_rates).to be_nil
123+
end
124+
end
125+
126+
context 'with JSON missing rate_by_service key' do
127+
it 'returns nil' do
128+
resp = make_response(payload: '{"other":"data"}')
129+
expect(resp.service_rates).to be_nil
130+
end
131+
end
132+
end
133+
134+
RSpec.describe 'Datadog::Tracing::Transport::Native::InternalErrorResponse#service_rates' do
135+
it 'returns nil' do
136+
resp = Datadog::Tracing::Transport::Native::InternalErrorResponse.new(RuntimeError.new('test'))
137+
expect(resp.service_rates).to be_nil
138+
end
139+
end

0 commit comments

Comments
 (0)