Skip to content

Commit 794fa98

Browse files
committed
SymDB remote: route diagnostics through component.logger
#5717 used Datadog.logger directly in Remote.process_change / enable_upload / disable_upload / parse_config — a Component Pattern violation, since the component was in scope at every call site and the logger was the dependency that should have been used. - Expose Component#logger via attr_reader (and update the RBS). - Replace Datadog.logger with component.logger in the four sites where component is available. The receiver-block fallback at remote.rb:48 keeps Datadog.logger because the component lookup itself may return nil there. - Thread the logger explicitly through parse_config(content, logger) rather than relying on a global. - Update the RBS for parse_config and remote_spec.rb's parse_config / component test doubles. Also adds a justification comment to the remote.rb:106 # steep:ignore NoMethod directive, matching the pattern already used at line 113.
1 parent 78301e1 commit 794fa98

5 files changed

Lines changed: 25 additions & 17 deletions

File tree

lib/datadog/symbol_database/component.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def self.build(settings, agent_settings, logger, telemetry: nil)
107107
end
108108
end
109109

110-
attr_reader :settings, :last_upload_time, :last_upload_scope_count, :upload_in_progress
110+
attr_reader :settings, :logger, :last_upload_time, :last_upload_scope_count, :upload_in_progress
111111

112112
# Initialize component.
113113
# @param settings [Configuration::Settings] Tracer settings
@@ -224,7 +224,10 @@ def stop_upload
224224
def wait_for_idle(timeout: 30)
225225
deadline = Datadog::Core::Utils::Time.get_time + timeout
226226
Component.upload_done_mutex.synchronize do
227-
until Component.send(:instance_variable_get, :@uploaded_this_process)
227+
# Read @uploaded_this_process directly: we already hold
228+
# Component.upload_done_mutex here, and uploaded_this_process?
229+
# would try to re-acquire it (non-reentrant), deadlocking.
230+
until Component.instance_variable_get(:@uploaded_this_process)
228231
remaining = deadline - Datadog::Core::Utils::Time.get_time
229232
return false if remaining <= 0
230233
Component.upload_done_cv.wait(Component.upload_done_mutex, remaining)

lib/datadog/symbol_database/remote.rb

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,13 @@ def process_change(component, change, telemetry)
102102
disable_upload(component)
103103
change.previous&.applied
104104
else
105-
Datadog.logger.debug { "symdb: unrecognized change type: #{change.type}" }
105+
component.logger.debug { "symdb: unrecognized change type: #{change.type}" }
106+
# Steep cannot narrow `change.content` from a respond_to? check — it sees
107+
# the Repository::Change union type where `Deleted` lacks `content`.
106108
change.content.errored("Unrecognized change type: #{change.type}") if change.respond_to?(:content) # steep:ignore NoMethod
107109
end
108110
rescue => e
109-
Datadog.logger.debug { "symdb: error processing remote config change: #{e.class}: #{e.message}" }
111+
component.logger.debug { "symdb: error processing remote config change: #{e.class}: #{e.message}" }
110112
telemetry&.report(e, description: 'symdb: error processing remote config change')
111113
# Rescue runs regardless of which branch raised — Steep cannot narrow the
112114
# union type from a respond_to? check.
@@ -120,17 +122,17 @@ def process_change(component, change, telemetry)
120122
# @return [void]
121123
# @api private
122124
def enable_upload(component, content)
123-
config = parse_config(content)
125+
config = parse_config(content, component.logger)
124126

125127
unless config
126128
return
127129
end
128130

129131
if config['upload_symbols']
130-
Datadog.logger.debug { "symdb: upload enabled via remote config" }
132+
component.logger.debug { "symdb: upload enabled via remote config" }
131133
component.start_upload
132134
else
133-
Datadog.logger.debug { "symdb: upload disabled in config" }
135+
component.logger.debug { "symdb: upload disabled in config" }
134136
end
135137
end
136138

@@ -139,28 +141,29 @@ def enable_upload(component, content)
139141
# @return [void]
140142
# @api private
141143
def disable_upload(component)
142-
Datadog.logger.debug { "symdb: upload disabled via remote config" }
144+
component.logger.debug { "symdb: upload disabled via remote config" }
143145
component.stop_upload
144146
end
145147

146148
# Parse and validate remote config content.
147149
# @param content [Content] Remote config content
150+
# @param logger [SymbolDatabase::Logger] Logger for invalid-config diagnostics
148151
# @return [Hash, nil] Parsed config or nil if invalid
149152
# @api private
150153
#
151154
# JSON::ParserError is intentionally NOT rescued here — it propagates to
152155
# process_change's rescue, which logs and reports to telemetry. Catching
153156
# it locally would swallow the error from telemetry observability.
154-
def parse_config(content)
157+
def parse_config(content, logger)
155158
config = JSON.parse(content.data)
156159

157160
unless config.is_a?(Hash)
158-
Datadog.logger.debug { "symdb: invalid config format: expected Hash, got #{config.class}" }
161+
logger.debug { "symdb: invalid config format: expected Hash, got #{config.class}" }
159162
return nil
160163
end
161164

162165
unless config.key?('upload_symbols')
163-
Datadog.logger.debug { "symdb: missing 'upload_symbols' key in config" }
166+
logger.debug { "symdb: missing 'upload_symbols' key in config" }
164167
return nil
165168
end
166169

sig/datadog/symbol_database/component.rbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ module Datadog
3737
def initialize: (Datadog::Core::Configuration::Settings settings, Datadog::Core::Configuration::AgentSettings agent_settings, SymbolDatabase::Logger logger, ?telemetry: Datadog::Core::Telemetry::Component?) -> void
3838

3939
attr_reader settings: Datadog::Core::Configuration::Settings
40+
attr_reader logger: SymbolDatabase::Logger
4041
attr_reader last_upload_time: ::Time?
4142
attr_reader last_upload_scope_count: ::Integer?
4243
attr_reader upload_in_progress: bool

sig/datadog/symbol_database/remote.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module Datadog
1919

2020
def self.disable_upload: (Component component) -> void
2121

22-
def self.parse_config: (Datadog::Core::Remote::Configuration::Content content) -> ::Hash[::String, untyped]?
22+
def self.parse_config: (Datadog::Core::Remote::Configuration::Content content, SymbolDatabase::Logger logger) -> ::Hash[::String, untyped]?
2323
end
2424
end
2525
end

spec/datadog/symbol_database/remote_spec.rb

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
require 'datadog/symbol_database/component'
1414

1515
RSpec.describe Datadog::SymbolDatabase::Remote do
16-
let(:component) { instance_double(Datadog::SymbolDatabase::Component) }
16+
let(:logger) { instance_double(Datadog::SymbolDatabase::Logger, debug: nil) }
17+
let(:component) { instance_double(Datadog::SymbolDatabase::Component, logger: logger) }
1718

1819
# Helper to create a mock change object
1920
def mock_change(type:, data:)
@@ -166,26 +167,26 @@ def mock_change(type:, data:)
166167
describe '.parse_config' do
167168
it 'parses valid upload_symbols config' do
168169
content = instance_double('Content', data: '{"upload_symbols": true}')
169-
result = described_class.send(:parse_config, content)
170+
result = described_class.send(:parse_config, content, logger)
170171
expect(result).to eq({'upload_symbols' => true})
171172
end
172173

173174
it 'returns nil for missing upload_symbols key' do
174175
content = instance_double('Content', data: '{"other": true}')
175-
result = described_class.send(:parse_config, content)
176+
result = described_class.send(:parse_config, content, logger)
176177
expect(result).to be_nil
177178
end
178179

179180
it 'raises JSON::ParserError for invalid JSON (caller process_change rescues + reports)' do
180181
content = instance_double('Content', data: 'bad json')
181182
expect {
182-
described_class.send(:parse_config, content)
183+
described_class.send(:parse_config, content, logger)
183184
}.to raise_error(JSON::ParserError)
184185
end
185186

186187
it 'returns nil for non-Hash JSON' do
187188
content = instance_double('Content', data: '[1, 2, 3]')
188-
result = described_class.send(:parse_config, content)
189+
result = described_class.send(:parse_config, content, logger)
189190
expect(result).to be_nil
190191
end
191192
end

0 commit comments

Comments
 (0)