Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/datadog/core/configuration/components.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def build_data_streams(settings, agent_settings, logger)
attr_reader \
:health_metrics,
:settings,
:agent_settings,
:logger,
:remote,
:profiler,
Expand All @@ -120,7 +121,7 @@ def initialize(settings)
# This agent_settings is intended for use within Core. If you require
# agent_settings within a product outside of core you should extend
# the Core resolver from within your product/component's namespace.
agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
@agent_settings = AgentSettingsResolver.call(settings, logger: @logger)

# Exposes agent capability information for detection by any components
@agent_info = Core::Environment::AgentInfo.new(agent_settings, logger: @logger)
Expand Down Expand Up @@ -162,7 +163,7 @@ def reconfigure_sampler(settings = Datadog.configuration)

# Starts up components
def startup!(settings, old_state: nil)
telemetry.start(old_state&.telemetry_enabled?)
telemetry.start(old_state&.telemetry_enabled?, components: self)

if settings.profiling.enabled
if profiler
Expand Down
10 changes: 7 additions & 3 deletions lib/datadog/core/telemetry/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,17 @@ def disable!
@worker&.enabled = false
end

def start(initial_event_is_change = false)
def start(initial_event_is_change = false, components:)
return if !@enabled

initial_event = if initial_event_is_change
Event::SynthAppClientConfigurationChange.new(agent_settings: @agent_settings)
Event::SynthAppClientConfigurationChange.new(
components: components,
)
else
Event::AppStarted.new(agent_settings: @agent_settings)
Event::AppStarted.new(
components: components,
)
end

@worker.start(initial_event)
Expand Down
101 changes: 52 additions & 49 deletions lib/datadog/core/telemetry/event/app_started.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ module Telemetry
module Event
# Telemetry class for the 'app-started' event
class AppStarted < Base
def initialize(agent_settings:)
@agent_settings = agent_settings
def initialize(components:)
# To not hold a reference to the component tree, generate
# the event payload here in the constructor.
@configuration = configuration(components.settings, components.agent_settings)
@install_signature = install_signature(components.settings)
@products = products(components)
end

def type
Expand All @@ -18,27 +22,28 @@ def type

def payload
{
products: products,
configuration: configuration,
install_signature: install_signature,
products: @products,
configuration: @configuration,
install_signature: @install_signature,
# DEV: Not implemented yet
# error: error, # Start-up errors
}
end

private

def products
def products(components)
# @type var products: Hash[Symbol, Hash[Symbol, Hash[Symbol, String | Integer] | bool | nil]]
products = {
appsec: {
enabled: Datadog::AppSec.enabled?,
# TODO take appsec status out of component tree?
enabled: components.settings.appsec.enabled,
},
profiler: {
enabled: Datadog::Profiling.enabled?,
enabled: !!components.profiler&.enabled?,
},
dynamic_instrumentation: {
enabled: defined?(Datadog::DI) && Datadog::DI.respond_to?(:enabled?) && Datadog::DI.enabled?,
enabled: !!components.dynamic_instrumentation,
}
}

Expand Down Expand Up @@ -73,12 +78,11 @@ def products

# standard:disable Metrics/AbcSize
# standard:disable Metrics/MethodLength
def configuration
config = Datadog.configuration
def configuration(settings, agent_settings)
seq_id = Event.configuration_sequence.next

# tracing.writer_options.buffer_size and tracing.writer_options.flush_interval have the same origin.
writer_option_origin = get_telemetry_origin(config, 'tracing.writer_options')
writer_option_origin = get_telemetry_origin(settings, 'tracing.writer_options')

list = [
# Only set using env var as of June 2025
Expand All @@ -100,69 +104,69 @@ def configuration
),

# Mix of env var, programmatic and default config, so we use unknown
conf_value('DD_AGENT_TRANSPORT', agent_transport, seq_id, 'unknown'), # rubocop:disable CustomCops/EnvStringValidationCop
conf_value('DD_AGENT_TRANSPORT', agent_transport(agent_settings), seq_id, 'unknown'), # rubocop:disable CustomCops/EnvStringValidationCop

# writer_options is defined as an option that has a Hash value.
conf_value(
'tracing.writer_options.buffer_size',
to_value(config.tracing.writer_options[:buffer_size]),
to_value(settings.tracing.writer_options[:buffer_size]),
seq_id,
writer_option_origin
),
conf_value(
'tracing.writer_options.flush_interval',
to_value(config.tracing.writer_options[:flush_interval]),
to_value(settings.tracing.writer_options[:flush_interval]),
seq_id,
writer_option_origin
),

conf_value('DD_AGENT_HOST', config.agent.host, seq_id, get_telemetry_origin(config, 'agent.host')),
conf_value('DD_AGENT_HOST', settings.agent.host, seq_id, get_telemetry_origin(settings, 'agent.host')),
conf_value(
'DD_TRACE_SAMPLE_RATE',
to_value(config.tracing.sampling.default_rate),
to_value(settings.tracing.sampling.default_rate),
seq_id,
get_telemetry_origin(config, 'tracing.sampling.default_rate')
get_telemetry_origin(settings, 'tracing.sampling.default_rate')
),
conf_value(
'DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED',
config.tracing.contrib.global_default_service_name.enabled,
settings.tracing.contrib.global_default_service_name.enabled,
seq_id,
get_telemetry_origin(config, 'tracing.contrib.global_default_service_name.enabled')
get_telemetry_origin(settings, 'tracing.contrib.global_default_service_name.enabled')
),
conf_value(
'DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED',
config.tracing.contrib.peer_service_defaults,
settings.tracing.contrib.peer_service_defaults,
seq_id,
get_telemetry_origin(config, 'tracing.contrib.peer_service_defaults')
get_telemetry_origin(settings, 'tracing.contrib.peer_service_defaults')
),
conf_value(
'DD_TRACE_DEBUG',
config.diagnostics.debug,
settings.diagnostics.debug,
seq_id,
get_telemetry_origin(config, 'diagnostics.debug')
get_telemetry_origin(settings, 'diagnostics.debug')
)
]

peer_service_mapping_str = ''
unless config.tracing.contrib.peer_service_mapping.empty?
peer_service_mapping = config.tracing.contrib.peer_service_mapping
unless settings.tracing.contrib.peer_service_mapping.empty?
peer_service_mapping = settings.tracing.contrib.peer_service_mapping
peer_service_mapping_str = peer_service_mapping.map { |key, value| "#{key}:#{value}" }.join(',')
end
list << conf_value(
'DD_TRACE_PEER_SERVICE_MAPPING',
peer_service_mapping_str,
seq_id,
get_telemetry_origin(config, 'tracing.contrib.peer_service_mapping')
get_telemetry_origin(settings, 'tracing.contrib.peer_service_mapping')
)

# Whitelist of configuration options to send in additional payload object
TARGET_OPTIONS.each do |option_path|
split_option = option_path.split('.')
list << conf_value(
option_path,
to_value(config.dig(*split_option)),
to_value(settings.dig(*split_option)),
seq_id,
get_telemetry_origin(config, option_path)
get_telemetry_origin(settings, option_path)
)
end

Expand All @@ -181,34 +185,34 @@ def configuration
)

# Add some more custom additional payload values here
if config.logger.instance
if settings.logger.instance
list << conf_value(
'logger.instance',
config.logger.instance.class.to_s,
settings.logger.instance.class.to_s,
seq_id,
get_telemetry_origin(config, 'logger.instance')
get_telemetry_origin(settings, 'logger.instance')
)
end
if config.respond_to?('appsec')
if settings.respond_to?('appsec')
list << conf_value(
'appsec.enabled',
config.dig('appsec', 'enabled'),
settings.dig('appsec', 'enabled'),
seq_id,
get_telemetry_origin(config, 'appsec.enabled')
get_telemetry_origin(settings, 'appsec.enabled')
)
list << conf_value(
'appsec.sca_enabled',
config.dig('appsec', 'sca_enabled'),
settings.dig('appsec', 'sca_enabled'),
seq_id,
get_telemetry_origin(config, 'appsec.sca_enabled')
get_telemetry_origin(settings, 'appsec.sca_enabled')
)
end
if config.respond_to?('ci')
if settings.respond_to?('ci')
list << conf_value(
'ci.enabled',
config.dig('ci', 'enabled'),
settings.dig('ci', 'enabled'),
seq_id,
get_telemetry_origin(config, 'ci.enabled')
get_telemetry_origin(settings, 'ci.enabled')
)
end

Expand All @@ -218,8 +222,8 @@ def configuration
# standard:enable Metrics/AbcSize
# standard:enable Metrics/MethodLength

def agent_transport
adapter = @agent_settings.adapter
def agent_transport(agent_settings)
adapter = agent_settings.adapter
if adapter == Datadog::Core::Transport::Ext::UnixSocket::ADAPTER
'UDS'
else
Expand Down Expand Up @@ -260,23 +264,22 @@ def to_value(value)
end
end

def install_signature
config = Datadog.configuration
def install_signature(settings)
{
install_id: config.dig('telemetry', 'install_id'),
install_type: config.dig('telemetry', 'install_type'),
install_time: config.dig('telemetry', 'install_time'),
install_id: settings.dig('telemetry', 'install_id'),
install_type: settings.dig('telemetry', 'install_type'),
install_time: settings.dig('telemetry', 'install_time'),
}
end

def get_telemetry_origin(config, config_path)
def get_telemetry_origin(settings, config_path)
split_option = config_path.split('.')
option_name = split_option.pop
return 'unknown' if option_name.nil?

# @type var parent_setting: Core::Configuration::Options
# @type var option: Core::Configuration::Option
parent_setting = config.dig(*split_option)
parent_setting = settings.dig(*split_option)
option = parent_setting.send(:resolve_option, option_name.to_sym)
option.precedence_set&.origin || 'unknown'
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def type

def payload
{
configuration: configuration,
configuration: @configuration,
}
end
end
Expand Down
3 changes: 1 addition & 2 deletions lib/datadog/profiling.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ def self.allocation_count

def self.enabled?
profiler = Datadog.send(:components).profiler
# Use .send(...) to avoid exposing the attr_reader as an API to the outside
!!profiler&.send(:scheduler)&.running?
!!profiler&.enabled?
end

def self.wait_until_running(timeout_seconds: 5)
Expand Down
4 changes: 4 additions & 0 deletions lib/datadog/profiling/profiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ def initialize(worker:, scheduler:)
@scheduler = scheduler
end

def enabled?
!!scheduler.running?
end

def start
after_fork! do
worker.reset_after_fork
Expand Down
6 changes: 6 additions & 0 deletions sig/datadog/core/configuration/components.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@ module Datadog

public

attr_reader settings: untyped

attr_reader agent_settings: untyped

attr_reader health_metrics: untyped

attr_reader logger: untyped

attr_reader profiler: untyped

attr_reader dynamic_instrumentation: untyped

attr_reader runtime_metrics: untyped

attr_reader tracer: untyped
Expand Down
2 changes: 1 addition & 1 deletion sig/datadog/core/telemetry/component.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module Datadog

def disable!: () -> void

def start: (?bool initial_event_is_change) -> void
def start: (?bool initial_event_is_change, components: Datadog::Core::Configuration::Components) -> void

def shutdown!: () -> void

Expand Down
14 changes: 6 additions & 8 deletions sig/datadog/core/telemetry/event/app_started.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,28 @@ module Datadog
module Telemetry
module Event
class AppStarted < Base
@agent_settings: Datadog::Core::Configuration::AgentSettings

def initialize: (agent_settings: Datadog::Core::Configuration::AgentSettings) -> void
def initialize: (components: Datadog::Core::Configuration::Components) -> void

def type: () -> "app-started"

def payload: () -> { products: untyped, configuration: untyped, install_signature: untyped }

private

def products: -> Hash[Symbol, Hash[Symbol, Hash[Symbol, String | Integer] | bool | nil]]
def products: (Datadog::Core::Configuration::Components components) -> Hash[Symbol, Hash[Symbol, Hash[Symbol, String | Integer] | bool | nil]]

TARGET_OPTIONS: Array[String]
def configuration: -> Array[Hash[Symbol, untyped]]
def configuration: (untyped settings, Core::Configuration::AgentSettings agent_settings) -> Array[Hash[Symbol, untyped]]

def agent_transport: () -> String
def agent_transport: (Core::Configuration::AgentSettings agent_settings) -> String

def conf_value: (String name, untyped value, Integer seq_id, String origin) -> Hash[Symbol, untyped]

def to_value: (Object value) -> Object

def install_signature: -> Hash[Symbol, Object]
def install_signature: (untyped settings) -> Hash[Symbol, Object]

def get_telemetry_origin: (untyped config, String config_path) -> String
def get_telemetry_origin: (untyped settings, String config_path) -> String
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions sig/datadog/profiling/profiler.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ module Datadog
scheduler: Datadog::Profiling::Scheduler
) -> void

def enabled?: () -> bool

def start: () -> void

def shutdown!: () -> void
Expand Down
2 changes: 2 additions & 0 deletions sig/datadog/profiling/scheduler.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ module Datadog

def start: (?on_failure_proc: ::Proc?) -> void

def running?: () -> bool

def reset_after_fork: () -> void
def mark_profiler_failed: () -> true
end
Expand Down
Loading
Loading