Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
31 changes: 30 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 45 additions & 10 deletions components-rs/remote_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,33 @@ type VecRemoteConfigCapabilities = libdd_common_ffi::Vec<RemoteConfigCapabilitie
pub static mut DDTRACE_REMOTE_CONFIG_CAPABILITIES: VecRemoteConfigCapabilities =
libdd_common_ffi::Vec::new();

struct ActiveDynamicConfig {
priority: u8,
configs: Vec<Configs>,
}

#[derive(Default)]
struct DynamicConfig {
active_config_path: Option<String>,
configs: Vec<Configs>,
active_configs: HashMap<String, ActiveDynamicConfig>,
merged_configs: Vec<Configs>,
old_config_values: HashMap<String, Option<OwnedZendString>>,
}

fn compute_merged_configs(active_configs: &HashMap<String, ActiveDynamicConfig>) -> Vec<Configs> {
let mut sorted: Vec<_> = active_configs.values().collect();
sorted.sort_by_key(|c| c.priority);
let mut seen = HashSet::new();
let mut merged = vec![];
for entry in sorted {
for config in &entry.configs {
if seen.insert(mem::discriminant(config)) {
merged.push(config.clone());
}
}
}
merged
}

pub struct RemoteConfigState {
manager: RemoteConfigManager,
live_debugger: LiveDebuggerState,
Expand Down Expand Up @@ -109,6 +129,7 @@ pub unsafe extern "C" fn ddog_init_remote_config(
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingLogsInjection);
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRate);
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRules);
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingMulticonfig);

DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmFeatures);
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::AsmAutoUserInstrumMode);
Expand Down Expand Up @@ -254,8 +275,8 @@ fn remove_old_configs(remote_config: &mut RemoteConfigState) {
for (name, val) in remote_config.dynamic_config.old_config_values.drain() {
reset_old_config(name.as_str(), val);
}
remote_config.dynamic_config.old_config_values.clear();
remote_config.dynamic_config.active_config_path = None;
remote_config.dynamic_config.active_configs.clear();
remote_config.dynamic_config.merged_configs.clear();
}

fn insert_new_configs(
Expand Down Expand Up @@ -338,14 +359,17 @@ pub extern "C" fn ddog_process_remote_configs(remote_config: &mut RemoteConfigSt
apply_config(rc_ref, debugger, limiter);
}
RemoteConfigData::DynamicConfig(config_data) => {
let priority = config_data.priority();
let configs: Vec<Configs> = config_data.lib_config.into();
if !configs.is_empty() {
remote_config.dynamic_config.active_configs
.insert(value.config_id, ActiveDynamicConfig { priority, configs });
let merged = compute_merged_configs(&remote_config.dynamic_config.active_configs);
insert_new_configs(
&mut remote_config.dynamic_config.old_config_values,
&mut remote_config.dynamic_config.configs,
configs,
&mut remote_config.dynamic_config.merged_configs,
merged,
);
remote_config.dynamic_config.active_config_path = Some(value.config_id);
}
}
RemoteConfigData::Ignored(_) => (),
Expand All @@ -360,8 +384,17 @@ pub extern "C" fn ddog_process_remote_configs(remote_config: &mut RemoteConfigSt
}
}
RemoteConfigProduct::ApmTracing => {
if Some(path.config_id) == remote_config.dynamic_config.active_config_path {
remove_old_configs(remote_config);
if remote_config.dynamic_config.active_configs.remove(&path.config_id).is_some() {
if remote_config.dynamic_config.active_configs.is_empty() {
remove_old_configs(remote_config);
} else {
let merged = compute_merged_configs(&remote_config.dynamic_config.active_configs);
insert_new_configs(
&mut remote_config.dynamic_config.old_config_values,
&mut remote_config.dynamic_config.merged_configs,
merged,
);
}
}
}
_ => (),
Expand Down Expand Up @@ -529,7 +562,7 @@ pub unsafe extern "C" fn ddog_remote_config_alter_dynamic_config(
{
let mut ret = false;
let config_name = config.to_utf8_lossy();
for config in remote_config.dynamic_config.configs.iter() {
for config in remote_config.dynamic_config.merged_configs.iter() {
let name = map_config_name(config);
if name == config_name.as_ref() {
let val = map_config_value(config);
Expand Down Expand Up @@ -559,6 +592,8 @@ pub unsafe extern "C" fn ddog_setup_remote_config(
pub extern "C" fn ddog_rshutdown_remote_config(remote_config: &mut RemoteConfigState) {
remote_config.live_debugger.spans_map.clear();
remote_config.dynamic_config.old_config_values.clear();
remote_config.dynamic_config.active_configs.clear();
remote_config.dynamic_config.merged_configs.clear();
remote_config.manager.unload_configs(&[
RemoteConfigProduct::ApmTracing,
RemoteConfigProduct::LiveDebugger,
Expand Down
3 changes: 3 additions & 0 deletions ext/remote_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@ static zend_string *dd_dynamic_configuration_update(ddog_CharSlice config, zend_
}
} else {
ZEND_ASSERT(mode == DDOG_DYNAMIC_CONFIG_UPDATE_MODE_WRITE);
ddog_RemoteConfigState *saved = DDTRACE_G(remote_config_state);
DDTRACE_G(remote_config_state) = NULL;
zend_alter_ini_entry(name, value, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
DDTRACE_G(remote_config_state) = saved;
zend_string_release(value);
}
zend_string_release(name);
Expand Down
2 changes: 1 addition & 1 deletion libdatadog
Submodule libdatadog updated 133 files
62 changes: 62 additions & 0 deletions tests/ext/remote_config/dynamic_config_multiconfig.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
--TEST--
Test dynamic config multiconfig priority merging
--SKIPIF--
<?php include __DIR__ . '/../includes/skipif_no_dev_env.inc'; ?>
--ENV--
DD_AGENT_HOST=request-replayer
DD_TRACE_AGENT_PORT=80
DD_TRACE_GENERATE_ROOT_SPAN=0
DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01
--INI--
datadog.trace.agent_test_session_token=remote-config/dynamic_config_multiconfig
--FILE--
<?php

require __DIR__ . "/remote_config.inc";
include __DIR__ . '/../includes/request_replayer.inc';

reset_request_replayer();
$rr = new RequestReplayer();

\DDTrace\start_span();

// Add both configs before sleeping so a single polling cycle sees both.
// Org-level: sets sample_rate=0.3 and log_injection=true.
// Specific service+env: overrides sample_rate=0.7, does not set log_injection.
$org_path = put_wildcard_dynamic_config_file([
"tracing_sample_rate" => 0.3,
"log_injection_enabled" => true,
]);
$specific_path = put_dynamic_config_file([
"tracing_sample_rate" => 0.7,
]);

sleep(20); // signal interrupts interrupt the sleep().

// Specific config wins for sample_rate; org-level provides log_injection.
print "After both configs:\n";
var_dump(ini_get("datadog.trace.sample_rate"));
var_dump(ini_get("datadog.logs_injection"));

del_rc_file($specific_path);

sleep(20); // signal interrupts interrupt the sleep().

// Only org-level remains: sample_rate falls back to 0.3.
print "After removing specific config:\n";
var_dump(ini_get("datadog.trace.sample_rate"));
var_dump(ini_get("datadog.logs_injection"));

?>
--CLEAN--
<?php
require __DIR__ . "/remote_config.inc";
reset_request_replayer();
?>
--EXPECT--
After both configs:
string(3) "0.7"
string(1) "1"
After removing specific config:
string(3) "0.3"
string(1) "1"
15 changes: 15 additions & 0 deletions tests/ext/remote_config/remote_config.inc
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,18 @@ function put_dynamic_config_file($configs, $service = null, $env = null) {
put_rc_file($path, $data, $service);
return $path;
}

function put_wildcard_dynamic_config_file($configs, $service = "*", $env = "*") {
$json = [
"action" => "enable",
"service_target" => [
"service" => $service,
"env" => $env,
],
"lib_config" => $configs,
];
$data = json_encode($json);
$path = "datadog/2/APM_TRACING/" . sha1($data) . "/config";
put_rc_file($path, $data);
return $path;
}
Loading