Skip to content
Draft
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
5 changes: 3 additions & 2 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions datadog-ffe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ publish = false
bench = false

[dependencies]
anyhow = { version = "1.0" }
datadog-remote-config = { path = "../datadog-remote-config", default-features = false }
faststr = { version = "0.2.23", default-features = false, features = ["serde"] }
serde = { version = "1.0", default-features = false, features = ["derive", "rc"] }
serde_json = { version = "1.0", default-features = false, features = ["std", "raw_value"] }
Expand Down
1 change: 1 addition & 0 deletions datadog-ffe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

mod flag_type;

pub mod remote_config;
pub mod rules_based;

pub use flag_type::{ExpectedFlagType, FlagType};
13 changes: 13 additions & 0 deletions datadog-ffe/src/remote_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0

use crate::rules_based::UniversalFlagConfig;
use datadog_remote_config::{RemoteConfigContent, RemoteConfigProduct};

impl RemoteConfigContent for UniversalFlagConfig {
const PRODUCT: RemoteConfigProduct = RemoteConfigProduct::FfeFlags;

fn parse(data: &[u8]) -> anyhow::Result<Self> {
Ok(UniversalFlagConfig::from_json(data.to_vec())?)
}
}
1 change: 1 addition & 0 deletions datadog-live-debugger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ publish = false

[dependencies]
anyhow = "1.0"
datadog-remote-config = { path = "../datadog-remote-config", default-features = false }
libdd-common = { path = "../libdd-common" }
libdd-data-pipeline = { path = "../libdd-data-pipeline" }
http-body-util = "0.1"
Expand Down
1 change: 1 addition & 0 deletions datadog-live-debugger/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ mod probe_defs;

pub mod debugger_defs;
mod redacted_names;
pub mod remote_config;
pub mod sender;

pub use expr_eval::*;
Expand Down
13 changes: 13 additions & 0 deletions datadog-live-debugger/src/remote_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2021-Present Datadog, Inc. https://www.datadoghq.com/
// SPDX-License-Identifier: Apache-2.0

use crate::probe_defs::LiveDebuggingData;
use datadog_remote_config::{RemoteConfigContent, RemoteConfigProduct};

impl RemoteConfigContent for LiveDebuggingData {
const PRODUCT: RemoteConfigProduct = RemoteConfigProduct::LiveDebugger;

fn parse(data: &[u8]) -> anyhow::Result<Self> {
crate::parse_json::parse(&String::from_utf8_lossy(data))
}
}
5 changes: 1 addition & 4 deletions datadog-remote-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,14 @@ client = [
"time",
"tracing"
]
live-debugger = ["datadog-live-debugger"]

regex-lite = ["libdd-common/regex-lite"]
ffe = ["datadog-ffe"]
test = ["hyper/server", "hyper-util"]

[dependencies]
anyhow = { version = "1.0" }
libdd-common = { path = "../libdd-common"}
libdd-trace-protobuf = { path = "../libdd-trace-protobuf", optional = true }
datadog-live-debugger = { path = "../datadog-live-debugger", optional = true }
datadog-ffe = { path = "../datadog-ffe", optional = true }
hyper = { workspace = true, optional = true, default-features = false }
http-body-util = {version = "0.1", optional = true }
http = { version = "1.1", optional = true }
Expand Down
9 changes: 6 additions & 3 deletions datadog-remote-config/examples/remote_config_fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use datadog_remote_config::fetch::{ConfigInvariants, ConfigOptions, SingleChange
use datadog_remote_config::file_change_tracker::{Change, FilePath};
use datadog_remote_config::file_storage::ParsedFileStorage;
use datadog_remote_config::RemoteConfigProduct::ApmTracing;
use datadog_remote_config::{RemoteConfigData, Target};
use datadog_remote_config::{RemoteConfigParsedData, Target};
use libdd_common::tag::Tag;
use libdd_common::Endpoint;
use std::time::Duration;
Expand Down Expand Up @@ -86,12 +86,15 @@ async fn main() {
}
}

fn print_file_contents(contents: &anyhow::Result<RemoteConfigData>) {
fn print_file_contents(contents: &anyhow::Result<Option<Box<dyn RemoteConfigParsedData>>>) {
// Note: these contents may be large. Do not actually print it fully in a non-dev env.
match contents {
Ok(data) => {
Ok(Some(data)) => {
println!("File contents: {data:?}");
}
Ok(None) => {
println!("Unregistered product, no parsed data");
}
Err(e) => {
println!("Failed parsing file: {e:?}");
}
Expand Down
6 changes: 3 additions & 3 deletions datadog-remote-config/src/config/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "test", derive(Default, Serialize))]
pub struct DynamicConfigTarget {
#[serde(default)]
Expand All @@ -13,7 +13,7 @@ pub struct DynamicConfigTarget {
pub env: Option<String>,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "test", derive(Serialize))]
pub struct DynamicConfigFile {
pub action: String,
Expand Down Expand Up @@ -76,7 +76,7 @@ pub struct TracingSamplingRule {
pub sample_rate: f64,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "test", derive(Default, Serialize))]
pub struct DynamicConfig {
pub(crate) tracing_header_tags: Option<Vec<TracingHeaderTag>>,
Expand Down
107 changes: 106 additions & 1 deletion datadog-remote-config/src/fetch/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ pub struct ConfigClientState {
targets_version: u64,
root_version: u64,
last_error: Option<String>,
/// Services discovered at runtime. Sent to the agent on each poll so it can route configs
/// targeting those services to this client. Updated out-of-band by the consumer
extra_services: Vec<String>,
}

impl Default for ConfigClientState {
Expand All @@ -231,10 +234,17 @@ impl Default for ConfigClientState {
targets_version: 0,
root_version: 1,
last_error: None,
extra_services: vec![],
}
}
}

impl ConfigClientState {
pub fn set_extra_services(&mut self, services: Vec<String>) {
self.extra_services = services;
}
}

impl<S: FileStorage> ConfigFetcher<S> {
pub fn new(file_storage: S, state: Arc<ConfigFetcherState<S::StoredFile>>) -> Self {
ConfigFetcher {
Expand Down Expand Up @@ -299,6 +309,7 @@ impl<S: FileStorage> ConfigFetcher<S> {
}
}
}
let extra_services = opaque_state.extra_services.clone();

let config_req = ClientGetConfigsRequest {
client: Some(libdd_trace_protobuf::remoteconfig::Client {
Expand All @@ -322,7 +333,7 @@ impl<S: FileStorage> ConfigFetcher<S> {
language: self.state.invariants.language.to_string(),
tracer_version: self.state.invariants.tracer_version.clone(),
service,
extra_services: vec![],
extra_services,
env,
app_version,
tags: tags.iter().map(|t| t.to_string()).collect(),
Expand Down Expand Up @@ -914,6 +925,100 @@ pub mod tests {
}
}

#[tokio::test]
#[cfg_attr(miri, ignore)]
async fn test_extra_services_forwarded_in_client_tracer() {
let server: Arc<RemoteConfigServer> = RemoteConfigServer::spawn();
server.files.lock().unwrap().insert(
PATH_FIRST.clone(),
(vec![DUMMY_TARGET.clone()], 1, "v1".to_string()),
);

let storage = Arc::new(Storage::default());
let mut fetcher = ConfigFetcher::new(
storage,
Arc::new(ConfigFetcherState::new(server.dummy_options().invariants)),
);
let mut opaque_state = ConfigClientState::default();

// Default: nothing set, agent receives an empty list.
fetcher
.fetch_once(
DUMMY_RUNTIME_ID,
DUMMY_TARGET.clone(),
&server.dummy_product_capabilities(),
"foo",
&mut opaque_state,
)
.await
.unwrap();
{
let req = server.last_request.lock().unwrap();
let tracer = req
.as_ref()
.unwrap()
.client
.as_ref()
.unwrap()
.client_tracer
.as_ref()
.unwrap();
assert!(tracer.extra_services.is_empty());
}

// After set_extra_services, the next poll forwards them to the agent.
opaque_state.set_extra_services(vec!["svc-a".to_string(), "svc-b".to_string()]);
fetcher
.fetch_once(
DUMMY_RUNTIME_ID,
DUMMY_TARGET.clone(),
&server.dummy_product_capabilities(),
"foo",
&mut opaque_state,
)
.await
.unwrap();
{
let req = server.last_request.lock().unwrap();
let tracer = req
.as_ref()
.unwrap()
.client
.as_ref()
.unwrap()
.client_tracer
.as_ref()
.unwrap();
assert_eq!(tracer.extra_services, &["svc-a", "svc-b"]);
}

// Replace-semantics: a subsequent set fully overrides the previous list.
opaque_state.set_extra_services(vec!["svc-c".to_string()]);
fetcher
.fetch_once(
DUMMY_RUNTIME_ID,
DUMMY_TARGET.clone(),
&server.dummy_product_capabilities(),
"foo",
&mut opaque_state,
)
.await
.unwrap();
{
let req = server.last_request.lock().unwrap();
let tracer = req
.as_ref()
.unwrap()
.client
.as_ref()
.unwrap()
.client_tracer
.as_ref()
.unwrap();
assert_eq!(tracer.extra_services, &["svc-c"]);
}
}

#[tokio::test]
#[cfg_attr(miri, ignore)]
async fn test_process_tags_forwarded_in_client_tracer() {
Expand Down
12 changes: 12 additions & 0 deletions datadog-remote-config/src/fetch/single.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ impl<S: FileStorage> SingleFetcher<S> {
pub fn set_config_state(&self, file: &RemoteConfigPath, state: ConfigApplyState) {
self.fetcher.set_config_state(file, state)
}

/// Update the set of services discovered at runtime
/// Sent to the agent on each subsequent poll so it can route configs targeting those
/// services to this client. Replace-semantics: the new vec fully overrides the previous one.
pub fn set_extra_services(&mut self, services: Vec<String>) {
self.opaque_state.set_extra_services(services);
}
}

pub struct SingleChangesFetcher<S: FileStorage>
Expand Down Expand Up @@ -117,4 +124,9 @@ where
pub fn set_config_state(&self, file: &S::StoredFile, state: ConfigApplyState) {
self.fetcher.set_config_state(file.path(), state)
}

/// See [`SingleFetcher::set_extra_services`].
pub fn set_extra_services(&mut self, services: Vec<String>) {
self.fetcher.set_extra_services(services);
}
}
3 changes: 0 additions & 3 deletions datadog-remote-config/src/fetch/test_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,6 @@ impl RemoteConfigServer {
tracer_version: "1.2.3".to_string(),
endpoint: self.endpoint.clone(),
},
#[cfg(not(feature = "live-debugger"))]
products: vec![RemoteConfigProduct::ApmTracing],
#[cfg(feature = "live-debugger")]
products: vec![
RemoteConfigProduct::ApmTracing,
RemoteConfigProduct::LiveDebugger,
Expand Down
Loading
Loading