Skip to content

Commit 97f1787

Browse files
committed
Support ApmTracingMulticonfig in dynamic config
Signed-off-by: Bob Weinand <bob.weinand@datadoghq.com>
1 parent 5bc467b commit 97f1787

File tree

6 files changed

+156
-12
lines changed

6 files changed

+156
-12
lines changed

Cargo.lock

Lines changed: 30 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components-rs/remote_config.rs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,33 @@ type VecRemoteConfigCapabilities = libdd_common_ffi::Vec<RemoteConfigCapabilitie
6060
pub static mut DDTRACE_REMOTE_CONFIG_CAPABILITIES: VecRemoteConfigCapabilities =
6161
libdd_common_ffi::Vec::new();
6262

63+
struct ActiveDynamicConfig {
64+
priority: u8,
65+
configs: Vec<Configs>,
66+
}
67+
6368
#[derive(Default)]
6469
struct DynamicConfig {
65-
active_config_path: Option<String>,
66-
configs: Vec<Configs>,
70+
active_configs: HashMap<String, ActiveDynamicConfig>,
71+
merged_configs: Vec<Configs>,
6772
old_config_values: HashMap<String, Option<OwnedZendString>>,
6873
}
6974

75+
fn compute_merged_configs(active_configs: &HashMap<String, ActiveDynamicConfig>) -> Vec<Configs> {
76+
let mut sorted: Vec<_> = active_configs.values().collect();
77+
sorted.sort_by_key(|c| c.priority);
78+
let mut seen = HashSet::new();
79+
let mut merged = vec![];
80+
for entry in sorted {
81+
for config in &entry.configs {
82+
if seen.insert(mem::discriminant(config)) {
83+
merged.push(config.clone());
84+
}
85+
}
86+
}
87+
merged
88+
}
89+
7090
pub struct RemoteConfigState {
7191
manager: RemoteConfigManager,
7292
live_debugger: LiveDebuggerState,
@@ -109,6 +129,7 @@ pub unsafe extern "C" fn ddog_init_remote_config(
109129
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingLogsInjection);
110130
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRate);
111131
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingSampleRules);
132+
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::ApmTracingMulticonfig);
112133

113134
DDTRACE_REMOTE_CONFIG_PRODUCTS.push(RemoteConfigProduct::AsmFeatures);
114135
DDTRACE_REMOTE_CONFIG_CAPABILITIES.push(RemoteConfigCapabilities::AsmAutoUserInstrumMode);
@@ -254,8 +275,8 @@ fn remove_old_configs(remote_config: &mut RemoteConfigState) {
254275
for (name, val) in remote_config.dynamic_config.old_config_values.drain() {
255276
reset_old_config(name.as_str(), val);
256277
}
257-
remote_config.dynamic_config.old_config_values.clear();
258-
remote_config.dynamic_config.active_config_path = None;
278+
remote_config.dynamic_config.active_configs.clear();
279+
remote_config.dynamic_config.merged_configs.clear();
259280
}
260281

261282
fn insert_new_configs(
@@ -338,14 +359,17 @@ pub extern "C" fn ddog_process_remote_configs(remote_config: &mut RemoteConfigSt
338359
apply_config(rc_ref, debugger, limiter);
339360
}
340361
RemoteConfigData::DynamicConfig(config_data) => {
362+
let priority = config_data.priority();
341363
let configs: Vec<Configs> = config_data.lib_config.into();
342364
if !configs.is_empty() {
365+
remote_config.dynamic_config.active_configs
366+
.insert(value.config_id, ActiveDynamicConfig { priority, configs });
367+
let merged = compute_merged_configs(&remote_config.dynamic_config.active_configs);
343368
insert_new_configs(
344369
&mut remote_config.dynamic_config.old_config_values,
345-
&mut remote_config.dynamic_config.configs,
346-
configs,
370+
&mut remote_config.dynamic_config.merged_configs,
371+
merged,
347372
);
348-
remote_config.dynamic_config.active_config_path = Some(value.config_id);
349373
}
350374
}
351375
RemoteConfigData::Ignored(_) => (),
@@ -360,8 +384,17 @@ pub extern "C" fn ddog_process_remote_configs(remote_config: &mut RemoteConfigSt
360384
}
361385
}
362386
RemoteConfigProduct::ApmTracing => {
363-
if Some(path.config_id) == remote_config.dynamic_config.active_config_path {
364-
remove_old_configs(remote_config);
387+
if remote_config.dynamic_config.active_configs.remove(&path.config_id).is_some() {
388+
if remote_config.dynamic_config.active_configs.is_empty() {
389+
remove_old_configs(remote_config);
390+
} else {
391+
let merged = compute_merged_configs(&remote_config.dynamic_config.active_configs);
392+
insert_new_configs(
393+
&mut remote_config.dynamic_config.old_config_values,
394+
&mut remote_config.dynamic_config.merged_configs,
395+
merged,
396+
);
397+
}
365398
}
366399
}
367400
_ => (),
@@ -529,7 +562,7 @@ pub unsafe extern "C" fn ddog_remote_config_alter_dynamic_config(
529562
{
530563
let mut ret = false;
531564
let config_name = config.to_utf8_lossy();
532-
for config in remote_config.dynamic_config.configs.iter() {
565+
for config in remote_config.dynamic_config.merged_configs.iter() {
533566
let name = map_config_name(config);
534567
if name == config_name.as_ref() {
535568
let val = map_config_value(config);
@@ -559,6 +592,8 @@ pub unsafe extern "C" fn ddog_setup_remote_config(
559592
pub extern "C" fn ddog_rshutdown_remote_config(remote_config: &mut RemoteConfigState) {
560593
remote_config.live_debugger.spans_map.clear();
561594
remote_config.dynamic_config.old_config_values.clear();
595+
remote_config.dynamic_config.active_configs.clear();
596+
remote_config.dynamic_config.merged_configs.clear();
562597
remote_config.manager.unload_configs(&[
563598
RemoteConfigProduct::ApmTracing,
564599
RemoteConfigProduct::LiveDebugger,

ext/remote_config.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,10 @@ static zend_string *dd_dynamic_configuration_update(ddog_CharSlice config, zend_
9999
}
100100
} else {
101101
ZEND_ASSERT(mode == DDOG_DYNAMIC_CONFIG_UPDATE_MODE_WRITE);
102+
ddog_RemoteConfigState *saved = DDTRACE_G(remote_config_state);
103+
DDTRACE_G(remote_config_state) = NULL;
102104
zend_alter_ini_entry(name, value, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
105+
DDTRACE_G(remote_config_state) = saved;
103106
zend_string_release(value);
104107
}
105108
zend_string_release(name);

libdatadog

Submodule libdatadog updated 133 files
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
Test dynamic config multiconfig priority merging
3+
--SKIPIF--
4+
<?php include __DIR__ . '/../includes/skipif_no_dev_env.inc'; ?>
5+
--ENV--
6+
DD_AGENT_HOST=request-replayer
7+
DD_TRACE_AGENT_PORT=80
8+
DD_TRACE_GENERATE_ROOT_SPAN=0
9+
DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS=0.01
10+
--INI--
11+
datadog.trace.agent_test_session_token=remote-config/dynamic_config_multiconfig
12+
--FILE--
13+
<?php
14+
15+
require __DIR__ . "/remote_config.inc";
16+
include __DIR__ . '/../includes/request_replayer.inc';
17+
18+
reset_request_replayer();
19+
$rr = new RequestReplayer();
20+
21+
\DDTrace\start_span();
22+
23+
// Add both configs before sleeping so a single polling cycle sees both.
24+
// Org-level: sets sample_rate=0.3 and log_injection=true.
25+
// Specific service+env: overrides sample_rate=0.7, does not set log_injection.
26+
$org_path = put_wildcard_dynamic_config_file([
27+
"tracing_sample_rate" => 0.3,
28+
"log_injection_enabled" => true,
29+
]);
30+
$specific_path = put_dynamic_config_file([
31+
"tracing_sample_rate" => 0.7,
32+
]);
33+
34+
sleep(20); // signal interrupts interrupt the sleep().
35+
36+
// Specific config wins for sample_rate; org-level provides log_injection.
37+
print "After both configs:\n";
38+
var_dump(ini_get("datadog.trace.sample_rate"));
39+
var_dump(ini_get("datadog.logs_injection"));
40+
41+
del_rc_file($specific_path);
42+
43+
sleep(20); // signal interrupts interrupt the sleep().
44+
45+
// Only org-level remains: sample_rate falls back to 0.3.
46+
print "After removing specific config:\n";
47+
var_dump(ini_get("datadog.trace.sample_rate"));
48+
var_dump(ini_get("datadog.logs_injection"));
49+
50+
?>
51+
--CLEAN--
52+
<?php
53+
require __DIR__ . "/remote_config.inc";
54+
reset_request_replayer();
55+
?>
56+
--EXPECT--
57+
After both configs:
58+
string(3) "0.7"
59+
string(1) "1"
60+
After removing specific config:
61+
string(3) "0.3"
62+
string(1) "1"

tests/ext/remote_config/remote_config.inc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,18 @@ function put_dynamic_config_file($configs, $service = null, $env = null) {
5656
put_rc_file($path, $data, $service);
5757
return $path;
5858
}
59+
60+
function put_wildcard_dynamic_config_file($configs, $service = "*", $env = "*") {
61+
$json = [
62+
"action" => "enable",
63+
"service_target" => [
64+
"service" => $service,
65+
"env" => $env,
66+
],
67+
"lib_config" => $configs,
68+
];
69+
$data = json_encode($json);
70+
$path = "datadog/2/APM_TRACING/" . sha1($data) . "/config";
71+
put_rc_file($path, $data);
72+
return $path;
73+
}

0 commit comments

Comments
 (0)