From fdb365f49da9935ea1d3ffa391393be5ab9d845e Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 7 Oct 2026 12:44:16 -0400 Subject: [PATCH 01/14] [SVLS-9883] Add DD_LOG_DEBUG_TARGETS to enable debug logs per target DD_LOG_DEBUG_TARGETS is a comma-separated list of tracing targets that log at debug level while DD_LOG_LEVEL stays at its normal level. For example, DD_LOG_DEBUG_TARGETS=cold_start_duration shows only the cold start step durations. Each entry is parsed on its own. An entry that does not parse, such as "cold_start_duration=trace", is logged as a warning and skipped, because the filter's expect() would otherwise fail startup. At DD_LOG_LEVEL=debug or trace the variable is ignored, since a target directive could only lower trace to debug. Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/bin/bottlecap/main.rs | 72 ++++++++++++++++++++++++++--- bottlecap/src/logger.rs | 3 +- 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 7aca77a3f..87be1e8a3 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -103,7 +103,7 @@ use tokio::time::Instant; use tokio::{sync::Mutex as TokioMutex, sync::mpsc::Sender}; use tokio_util::sync::CancellationToken; use tracing::{debug, error, warn}; -use tracing_subscriber::EnvFilter; +use tracing_subscriber::{EnvFilter, filter::Directive}; use ustr::Ustr; fn resolve_dsm_service( @@ -239,13 +239,12 @@ fn enable_logging_subsystem() { ) .unwrap_or(LogLevel::Info); - let env_filter = format!( - "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}", + let (env_filter, invalid_debug_targets) = build_env_filter( + log_level, + &std::env::var("DD_LOG_DEBUG_TARGETS").unwrap_or_default(), ); let subscriber = tracing_subscriber::fmt::Subscriber::builder() - .with_env_filter( - EnvFilter::try_new(env_filter).expect("could not parse log level in configuration"), - ) + .with_env_filter(env_filter) .with_level(true) .with_thread_names(false) .with_thread_ids(false) @@ -257,9 +256,39 @@ fn enable_logging_subsystem() { .finish(); tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); + if !invalid_debug_targets.is_empty() { + warn!("Ignoring invalid DD_LOG_DEBUG_TARGETS entries: {invalid_debug_targets:?}"); + } debug!("Logging subsystem enabled"); } +/// Builds the log filter from `DD_LOG_LEVEL` and `DD_LOG_DEBUG_TARGETS`, a comma-separated +/// list of tracing targets to log at debug level. Returns the entries that do not parse, so +/// that a typo is logged instead of failing startup. +fn build_env_filter(log_level: LogLevel, debug_targets: &str) -> (EnvFilter, Vec) { + let mut env_filter = EnvFilter::try_new(format!( + "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}", + )) + .expect("could not parse log level in configuration"); + let mut invalid_targets = Vec::new(); + // At debug or trace, every target already logs at debug. A target directive would only + // lower a trace level to debug. + if matches!(log_level, LogLevel::Debug | LogLevel::Trace) { + return (env_filter, invalid_targets); + } + for target in debug_targets + .split(',') + .map(str::trim) + .filter(|t| !t.is_empty()) + { + match format!("{target}=debug").parse::() { + Ok(directive) => env_filter = env_filter.add_directive(directive), + Err(_) => invalid_targets.push(target.to_string()), + } + } + (env_filter, invalid_targets) +} + /// Returns the appropriate flush strategy for the given mode. /// In managed instance mode, continuous flush strategy is required for optimal performance. /// If a different strategy is configured, this function will override it and log an info message. @@ -1614,3 +1643,34 @@ mod dsm_config_tests { assert_eq!(resolve_dsm_service(None, None), "aws.lambda"); } } + +#[cfg(test)] +mod env_filter_tests { + use super::{LogLevel, build_env_filter}; + + #[test] + fn adds_debug_directive_per_target() { + let (filter, invalid) = + build_env_filter(LogLevel::Info, " cold_start_duration, bottlecap::traces ,"); + let filter = filter.to_string(); + assert!(filter.contains("cold_start_duration=debug")); + assert!(filter.contains("bottlecap::traces=debug")); + assert!(invalid.is_empty()); + } + + #[test] + fn skips_invalid_targets() { + let (filter, invalid) = build_env_filter( + LogLevel::Info, + "cold_start_duration=trace,cold_start_duration", + ); + assert!(filter.to_string().contains("cold_start_duration=debug")); + assert_eq!(invalid, vec!["cold_start_duration=trace"]); + } + + #[test] + fn ignores_targets_at_trace_level() { + let (filter, _) = build_env_filter(LogLevel::Trace, "cold_start_duration"); + assert!(!filter.to_string().contains("cold_start_duration")); + } +} diff --git a/bottlecap/src/logger.rs b/bottlecap/src/logger.rs index 1752e2f97..7e1fc37aa 100644 --- a/bottlecap/src/logger.rs +++ b/bottlecap/src/logger.rs @@ -6,7 +6,8 @@ use tracing_subscriber::fmt::{ }; use tracing_subscriber::registry::LookupSpan; -/// Tracing target for the duration of each cold start step. +/// Tracing target for the duration of each cold start step. Enable it alone with +/// `DD_LOG_DEBUG_TARGETS=cold_start_duration`. pub const COLD_START_DURATION: &str = "cold_start_duration"; /// Logs at debug level how long `step` took since `start`, under a duration target such as From 246a2e98e1e6e37f587a36ba898c8e274cc5267d Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:22:01 -0400 Subject: [PATCH 02/14] [SVLS-9883] Use trace_flush_duration in the env filter test Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/bin/bottlecap/main.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 87be1e8a3..074d98245 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -1650,11 +1650,13 @@ mod env_filter_tests { #[test] fn adds_debug_directive_per_target() { - let (filter, invalid) = - build_env_filter(LogLevel::Info, " cold_start_duration, bottlecap::traces ,"); + let (filter, invalid) = build_env_filter( + LogLevel::Info, + " cold_start_duration, trace_flush_duration ,", + ); let filter = filter.to_string(); assert!(filter.contains("cold_start_duration=debug")); - assert!(filter.contains("bottlecap::traces=debug")); + assert!(filter.contains("trace_flush_duration=debug")); assert!(invalid.is_empty()); } From 981ee9d75556bb968a21b8d89b3f8490d25512c3 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:31:51 -0400 Subject: [PATCH 03/14] [SVLS-9883] Replace DD_LOG_DEBUG_TARGETS with DD_LOG_LEVEL_BY_TARGET DD_LOG_LEVEL_BY_TARGET takes comma-separated `target=level` entries in the RUST_LOG syntax, so that a target can also get a level other than debug, or be made quieter than DD_LOG_LEVEL. An entry with no level turns on all levels for that target. Entries also override the built-in h2, hyper, reqwest and rustls defaults. Each entry is used as written, so the rule that ignored the variable at DD_LOG_LEVEL=debug or trace no longer applies. Invalid entries are still logged as a warning and skipped. Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/bin/bottlecap/main.rs | 57 ++++++++++++++--------------- bottlecap/src/logger.rs | 2 +- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 074d98245..24d00865b 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -239,9 +239,9 @@ fn enable_logging_subsystem() { ) .unwrap_or(LogLevel::Info); - let (env_filter, invalid_debug_targets) = build_env_filter( + let (env_filter, invalid_entries) = build_env_filter( log_level, - &std::env::var("DD_LOG_DEBUG_TARGETS").unwrap_or_default(), + &std::env::var("DD_LOG_LEVEL_BY_TARGET").unwrap_or_default(), ); let subscriber = tracing_subscriber::fmt::Subscriber::builder() .with_env_filter(env_filter) @@ -256,37 +256,33 @@ fn enable_logging_subsystem() { .finish(); tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); - if !invalid_debug_targets.is_empty() { - warn!("Ignoring invalid DD_LOG_DEBUG_TARGETS entries: {invalid_debug_targets:?}"); + if !invalid_entries.is_empty() { + warn!("Ignoring invalid DD_LOG_LEVEL_BY_TARGET entries: {invalid_entries:?}"); } debug!("Logging subsystem enabled"); } -/// Builds the log filter from `DD_LOG_LEVEL` and `DD_LOG_DEBUG_TARGETS`, a comma-separated -/// list of tracing targets to log at debug level. Returns the entries that do not parse, so -/// that a typo is logged instead of failing startup. -fn build_env_filter(log_level: LogLevel, debug_targets: &str) -> (EnvFilter, Vec) { +/// Builds the log filter from `DD_LOG_LEVEL` and `DD_LOG_LEVEL_BY_TARGET`, a comma-separated +/// list of `target=level` entries in the `RUST_LOG` syntax. An entry with no level turns on all +/// levels for that target. Returns the entries that do not parse, so that a typo is logged +/// instead of failing startup. +fn build_env_filter(log_level: LogLevel, levels_by_target: &str) -> (EnvFilter, Vec) { let mut env_filter = EnvFilter::try_new(format!( "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}", )) .expect("could not parse log level in configuration"); - let mut invalid_targets = Vec::new(); - // At debug or trace, every target already logs at debug. A target directive would only - // lower a trace level to debug. - if matches!(log_level, LogLevel::Debug | LogLevel::Trace) { - return (env_filter, invalid_targets); - } - for target in debug_targets + let mut invalid_entries = Vec::new(); + for entry in levels_by_target .split(',') .map(str::trim) - .filter(|t| !t.is_empty()) + .filter(|e| !e.is_empty()) { - match format!("{target}=debug").parse::() { + match entry.parse::() { Ok(directive) => env_filter = env_filter.add_directive(directive), - Err(_) => invalid_targets.push(target.to_string()), + Err(_) => invalid_entries.push(entry.to_string()), } } - (env_filter, invalid_targets) + (env_filter, invalid_entries) } /// Returns the appropriate flush strategy for the given mode. @@ -1649,30 +1645,33 @@ mod env_filter_tests { use super::{LogLevel, build_env_filter}; #[test] - fn adds_debug_directive_per_target() { + fn adds_directive_per_entry() { let (filter, invalid) = build_env_filter( LogLevel::Info, - " cold_start_duration, trace_flush_duration ,", + " cold_start_duration=debug, trace_flush_duration ,", ); let filter = filter.to_string(); assert!(filter.contains("cold_start_duration=debug")); - assert!(filter.contains("trace_flush_duration=debug")); + assert!(filter.contains("trace_flush_duration=trace")); assert!(invalid.is_empty()); } #[test] - fn skips_invalid_targets() { + fn skips_invalid_entries() { let (filter, invalid) = build_env_filter( LogLevel::Info, - "cold_start_duration=trace,cold_start_duration", + "cold_start_duration=verbose,trace_flush_duration=debug", ); - assert!(filter.to_string().contains("cold_start_duration=debug")); - assert_eq!(invalid, vec!["cold_start_duration=trace"]); + assert!(filter.to_string().contains("trace_flush_duration=debug")); + assert_eq!(invalid, vec!["cold_start_duration=verbose"]); } #[test] - fn ignores_targets_at_trace_level() { - let (filter, _) = build_env_filter(LogLevel::Trace, "cold_start_duration"); - assert!(!filter.to_string().contains("cold_start_duration")); + fn overrides_default_levels() { + let (filter, _) = build_env_filter(LogLevel::Debug, "bottlecap::logs=warn,h2=debug"); + let filter = filter.to_string(); + assert!(filter.contains("bottlecap::logs=warn")); + assert!(filter.contains("h2=debug")); + assert!(!filter.contains("h2=off")); } } diff --git a/bottlecap/src/logger.rs b/bottlecap/src/logger.rs index 7e1fc37aa..37481b2e3 100644 --- a/bottlecap/src/logger.rs +++ b/bottlecap/src/logger.rs @@ -7,7 +7,7 @@ use tracing_subscriber::fmt::{ use tracing_subscriber::registry::LookupSpan; /// Tracing target for the duration of each cold start step. Enable it alone with -/// `DD_LOG_DEBUG_TARGETS=cold_start_duration`. +/// `DD_LOG_LEVEL_BY_TARGET=cold_start_duration=debug`. pub const COLD_START_DURATION: &str = "cold_start_duration"; /// Logs at debug level how long `step` took since `start`, under a duration target such as From 16f683a73baf83ff6689bab0cfe305492d3d1624 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:48:46 -0400 Subject: [PATCH 04/14] [SVLS-9883] Document that target names must not be prefixes of each other Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/logger.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bottlecap/src/logger.rs b/bottlecap/src/logger.rs index 37481b2e3..45d33c79a 100644 --- a/bottlecap/src/logger.rs +++ b/bottlecap/src/logger.rs @@ -6,6 +6,9 @@ use tracing_subscriber::fmt::{ }; use tracing_subscriber::registry::LookupSpan; +// `DD_LOG_LEVEL_BY_TARGET` matches a target by text prefix, so no target name may start with +// another one: an entry for `trace_flush` would also match `trace_flush_duration`. + /// Tracing target for the duration of each cold start step. Enable it alone with /// `DD_LOG_LEVEL_BY_TARGET=cold_start_duration=debug`. pub const COLD_START_DURATION: &str = "cold_start_duration"; From 225e4965e81ec10793402bdc4c609ad9b2d43890 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 7 Oct 2026 15:19:31 -0400 Subject: [PATCH 05/14] [SVLS-9883] Accept filter directives in DD_LOG_LEVEL Drop DD_LOG_LEVEL_BY_TARGET and read the same `target=level` directives from DD_LOG_LEVEL, for example `info,cold_start_duration=debug`. This matches the Agent Data Plane and datadog-serverless-compat, which both accept directives in DD_LOG_LEVEL. A plain level still works as before. Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/bin/bottlecap/main.rs | 92 +++++++++++++++-------------- bottlecap/src/logger.rs | 4 +- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 24d00865b..6809a1f9a 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -25,7 +25,6 @@ use bottlecap::{ self, Config, aws::{AwsConfig, build_lambda_function_arn}, flush_strategy::{FlushStrategy, PeriodicStrategy}, - log_level::LogLevel, }, event_bus::{Event, EventBus}, extension::{ @@ -98,7 +97,7 @@ use dogstatsd::{ }; use libdd_trace_obfuscation::obfuscation_config; use reqwest::Client; -use std::{collections::hash_map, env, path::Path, str::FromStr, sync::Arc}; +use std::{collections::hash_map, env, path::Path, sync::Arc}; use tokio::time::Instant; use tokio::{sync::Mutex as TokioMutex, sync::mpsc::Sender}; use tokio_util::sync::CancellationToken; @@ -232,17 +231,8 @@ fn init_ustr() { } fn enable_logging_subsystem() { - let log_level = LogLevel::from_str( - std::env::var("DD_LOG_LEVEL") - .unwrap_or("info".to_string()) - .as_str(), - ) - .unwrap_or(LogLevel::Info); - - let (env_filter, invalid_entries) = build_env_filter( - log_level, - &std::env::var("DD_LOG_LEVEL_BY_TARGET").unwrap_or_default(), - ); + let (env_filter, invalid_entries) = + build_env_filter(&std::env::var("DD_LOG_LEVEL").unwrap_or_default()); let subscriber = tracing_subscriber::fmt::Subscriber::builder() .with_env_filter(env_filter) .with_level(true) @@ -257,22 +247,22 @@ fn enable_logging_subsystem() { tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); if !invalid_entries.is_empty() { - warn!("Ignoring invalid DD_LOG_LEVEL_BY_TARGET entries: {invalid_entries:?}"); + warn!("Ignoring invalid DD_LOG_LEVEL entries: {invalid_entries:?}"); } debug!("Logging subsystem enabled"); } -/// Builds the log filter from `DD_LOG_LEVEL` and `DD_LOG_LEVEL_BY_TARGET`, a comma-separated -/// list of `target=level` entries in the `RUST_LOG` syntax. An entry with no level turns on all -/// levels for that target. Returns the entries that do not parse, so that a typo is logged -/// instead of failing startup. -fn build_env_filter(log_level: LogLevel, levels_by_target: &str) -> (EnvFilter, Vec) { - let mut env_filter = EnvFilter::try_new(format!( - "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}", - )) - .expect("could not parse log level in configuration"); +/// Builds the log filter from `DD_LOG_LEVEL`: a level such as `debug`, or comma-separated +/// directives in the `RUST_LOG` syntax, such as `info,cold_start_duration=debug`. The default +/// level is info. A directive with no level turns on all levels for its target. Returns the +/// entries that do not parse, so that a typo is logged instead of failing startup. +fn build_env_filter(log_level: &str) -> (EnvFilter, Vec) { + let mut env_filter = EnvFilter::try_new( + "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,info", + ) + .expect("could not parse default log filter"); let mut invalid_entries = Vec::new(); - for entry in levels_by_target + for entry in log_level .split(',') .map(str::trim) .filter(|e| !e.is_empty()) @@ -1642,36 +1632,52 @@ mod dsm_config_tests { #[cfg(test)] mod env_filter_tests { - use super::{LogLevel, build_env_filter}; + use super::build_env_filter; + + fn directives(log_level: &str) -> (Vec, Vec) { + let (filter, invalid) = build_env_filter(log_level); + let directives = filter.to_string().split(',').map(String::from).collect(); + (directives, invalid) + } + + #[test] + fn defaults_to_info() { + let (directives, invalid) = directives(""); + assert!(directives.contains(&"info".to_string())); + assert!(invalid.is_empty()); + } + + #[test] + fn plain_level_replaces_default() { + let (directives, _) = directives("DEBUG"); + assert!(directives.contains(&"debug".to_string())); + assert!(!directives.contains(&"info".to_string())); + } #[test] fn adds_directive_per_entry() { - let (filter, invalid) = build_env_filter( - LogLevel::Info, - " cold_start_duration=debug, trace_flush_duration ,", - ); - let filter = filter.to_string(); - assert!(filter.contains("cold_start_duration=debug")); - assert!(filter.contains("trace_flush_duration=trace")); + let (directives, invalid) = + directives(" warn, cold_start_duration=debug, trace_flush_duration ,"); + assert!(directives.contains(&"warn".to_string())); + assert!(directives.contains(&"cold_start_duration=debug".to_string())); + assert!(directives.contains(&"trace_flush_duration=trace".to_string())); assert!(invalid.is_empty()); } #[test] fn skips_invalid_entries() { - let (filter, invalid) = build_env_filter( - LogLevel::Info, - "cold_start_duration=verbose,trace_flush_duration=debug", - ); - assert!(filter.to_string().contains("trace_flush_duration=debug")); + let (directives, invalid) = + directives("cold_start_duration=verbose,trace_flush_duration=debug"); + assert!(directives.contains(&"info".to_string())); + assert!(directives.contains(&"trace_flush_duration=debug".to_string())); assert_eq!(invalid, vec!["cold_start_duration=verbose"]); } #[test] - fn overrides_default_levels() { - let (filter, _) = build_env_filter(LogLevel::Debug, "bottlecap::logs=warn,h2=debug"); - let filter = filter.to_string(); - assert!(filter.contains("bottlecap::logs=warn")); - assert!(filter.contains("h2=debug")); - assert!(!filter.contains("h2=off")); + fn overrides_default_target_levels() { + let (directives, _) = directives("debug,bottlecap::logs=warn,h2=debug"); + assert!(directives.contains(&"bottlecap::logs=warn".to_string())); + assert!(directives.contains(&"h2=debug".to_string())); + assert!(!directives.contains(&"h2=off".to_string())); } } diff --git a/bottlecap/src/logger.rs b/bottlecap/src/logger.rs index 45d33c79a..d36347d44 100644 --- a/bottlecap/src/logger.rs +++ b/bottlecap/src/logger.rs @@ -6,11 +6,11 @@ use tracing_subscriber::fmt::{ }; use tracing_subscriber::registry::LookupSpan; -// `DD_LOG_LEVEL_BY_TARGET` matches a target by text prefix, so no target name may start with +// `DD_LOG_LEVEL` matches a target by text prefix, so no target name may start with // another one: an entry for `trace_flush` would also match `trace_flush_duration`. /// Tracing target for the duration of each cold start step. Enable it alone with -/// `DD_LOG_LEVEL_BY_TARGET=cold_start_duration=debug`. +/// `DD_LOG_LEVEL=info,cold_start_duration=debug`. pub const COLD_START_DURATION: &str = "cold_start_duration"; /// Logs at debug level how long `step` took since `start`, under a duration target such as From 0e706b3392d5131a77a5997158db34a567a87d73 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 7 Oct 2026 15:30:20 -0400 Subject: [PATCH 06/14] [SVLS-9883] Bump serverless-components for directive-aware DD_LOG_LEVEL Without it, the config crate logs "Invalid log level" at ERROR on each cold start when DD_LOG_LEVEL holds filter directives. Co-Authored-By: Claude Opus 5.5 --- bottlecap/Cargo.lock | 8 ++++---- bottlecap/Cargo.toml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 61b5cf23d..7bd50638d 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -868,7 +868,7 @@ dependencies = [ [[package]] name = "datadog-agent-config" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" dependencies = [ "datadog-opentelemetry", "dogstatsd", @@ -886,12 +886,12 @@ dependencies = [ [[package]] name = "datadog-agent-trace-sampler" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" dependencies = [ "reqwest", "rustls", @@ -1070,7 +1070,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" dependencies = [ "datadog-protos", "ddsketch-agent", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 07b8f8e0b..7d313e904 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -95,10 +95,10 @@ libdd-trace-normalization = "3.0.1" libdd-trace-obfuscation = { version = "6.0.0", default-features = false } libdd-trace-stats = { version = "7.0.0", default-features = false } datadog-opentelemetry = { version = "0.5.2", default-features = false, features = ["_unstable_propagation"] } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } -datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } -datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } +datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } +datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] From 35ea498505f2cd883d58059e2a4580851305b632 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 7 Oct 2026 15:52:40 -0400 Subject: [PATCH 07/14] [SVLS-9883] Bump serverless-components to the latest commit of #178 Co-Authored-By: Claude Opus 5.5 --- bottlecap/Cargo.lock | 8 ++++---- bottlecap/Cargo.toml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 7bd50638d..052ad8ce7 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -868,7 +868,7 @@ dependencies = [ [[package]] name = "datadog-agent-config" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" +source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" dependencies = [ "datadog-opentelemetry", "dogstatsd", @@ -886,12 +886,12 @@ dependencies = [ [[package]] name = "datadog-agent-trace-sampler" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" +source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" +source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" dependencies = [ "reqwest", "rustls", @@ -1070,7 +1070,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=bec7a5f9dddc97985f5307227cb4dbb8c814192f#bec7a5f9dddc97985f5307227cb4dbb8c814192f" +source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" dependencies = [ "datadog-protos", "ddsketch-agent", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 7d313e904..d9b5c90e7 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -95,10 +95,10 @@ libdd-trace-normalization = "3.0.1" libdd-trace-obfuscation = { version = "6.0.0", default-features = false } libdd-trace-stats = { version = "7.0.0", default-features = false } datadog-opentelemetry = { version = "0.5.2", default-features = false, features = ["_unstable_propagation"] } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } -datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } -datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "bec7a5f9dddc97985f5307227cb4dbb8c814192f", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } +datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } +datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] From 015e783aef4c16be068fc270782e39691e55ce35 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Thu, 8 Oct 2026 12:34:58 -0400 Subject: [PATCH 08/14] [SVLS-9883] Bump serverless-components to the rebased #178 Co-Authored-By: Claude Opus 5.5 --- bottlecap/Cargo.lock | 8 ++++---- bottlecap/Cargo.toml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 052ad8ce7..bc61248a1 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -868,7 +868,7 @@ dependencies = [ [[package]] name = "datadog-agent-config" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" +source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" dependencies = [ "datadog-opentelemetry", "dogstatsd", @@ -886,12 +886,12 @@ dependencies = [ [[package]] name = "datadog-agent-trace-sampler" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" +source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" +source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" dependencies = [ "reqwest", "rustls", @@ -1070,7 +1070,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=77adbb7697b05b7e7557bc8a59c5d795fe331693#77adbb7697b05b7e7557bc8a59c5d795fe331693" +source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" dependencies = [ "datadog-protos", "ddsketch-agent", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index d9b5c90e7..1e1bdbfbc 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -95,10 +95,10 @@ libdd-trace-normalization = "3.0.1" libdd-trace-obfuscation = { version = "6.0.0", default-features = false } libdd-trace-stats = { version = "7.0.0", default-features = false } datadog-opentelemetry = { version = "0.5.2", default-features = false, features = ["_unstable_propagation"] } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } -datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } -datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "77adbb7697b05b7e7557bc8a59c5d795fe331693", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } +datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } +datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] From bf67a210f17e5b5064e4a047e459ed72ab3b6fb3 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Fri, 9 Oct 2026 11:44:45 -0400 Subject: [PATCH 09/14] [SVLS-9883] Go back to DD_LOG_LEVEL_BY_TARGET DD_LOG_LEVEL is also read by the Datadog libraries and tracers in the function, and they accept only a plain level, so directives there would change or break their logging. A separate variable that only the extension reads avoids that, and no longer needs the serverless-components change. Restores the code of 2afd657b and documents that targets include dependency module paths, such as `dogstatsd`. Co-Authored-By: Claude Opus 5.5 --- bottlecap/Cargo.lock | 8 +-- bottlecap/Cargo.toml | 8 +-- bottlecap/src/bin/bottlecap/main.rs | 93 ++++++++++++++--------------- bottlecap/src/logger.rs | 4 +- 4 files changed, 54 insertions(+), 59 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index bc61248a1..61b5cf23d 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -868,7 +868,7 @@ dependencies = [ [[package]] name = "datadog-agent-config" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" +source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" dependencies = [ "datadog-opentelemetry", "dogstatsd", @@ -886,12 +886,12 @@ dependencies = [ [[package]] name = "datadog-agent-trace-sampler" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" +source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" +source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" dependencies = [ "reqwest", "rustls", @@ -1070,7 +1070,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=254e9bd7a259eef08067f1ea565199fadb78b325#254e9bd7a259eef08067f1ea565199fadb78b325" +source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" dependencies = [ "datadog-protos", "ddsketch-agent", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 1e1bdbfbc..07b8f8e0b 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -95,10 +95,10 @@ libdd-trace-normalization = "3.0.1" libdd-trace-obfuscation = { version = "6.0.0", default-features = false } libdd-trace-stats = { version = "7.0.0", default-features = false } datadog-opentelemetry = { version = "0.5.2", default-features = false, features = ["_unstable_propagation"] } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } -datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } -datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "254e9bd7a259eef08067f1ea565199fadb78b325", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } +datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } +datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 6809a1f9a..092bc0cd3 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -25,6 +25,7 @@ use bottlecap::{ self, Config, aws::{AwsConfig, build_lambda_function_arn}, flush_strategy::{FlushStrategy, PeriodicStrategy}, + log_level::LogLevel, }, event_bus::{Event, EventBus}, extension::{ @@ -97,7 +98,7 @@ use dogstatsd::{ }; use libdd_trace_obfuscation::obfuscation_config; use reqwest::Client; -use std::{collections::hash_map, env, path::Path, sync::Arc}; +use std::{collections::hash_map, env, path::Path, str::FromStr, sync::Arc}; use tokio::time::Instant; use tokio::{sync::Mutex as TokioMutex, sync::mpsc::Sender}; use tokio_util::sync::CancellationToken; @@ -231,8 +232,17 @@ fn init_ustr() { } fn enable_logging_subsystem() { - let (env_filter, invalid_entries) = - build_env_filter(&std::env::var("DD_LOG_LEVEL").unwrap_or_default()); + let log_level = LogLevel::from_str( + std::env::var("DD_LOG_LEVEL") + .unwrap_or("info".to_string()) + .as_str(), + ) + .unwrap_or(LogLevel::Info); + + let (env_filter, invalid_entries) = build_env_filter( + log_level, + &std::env::var("DD_LOG_LEVEL_BY_TARGET").unwrap_or_default(), + ); let subscriber = tracing_subscriber::fmt::Subscriber::builder() .with_env_filter(env_filter) .with_level(true) @@ -247,22 +257,23 @@ fn enable_logging_subsystem() { tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); if !invalid_entries.is_empty() { - warn!("Ignoring invalid DD_LOG_LEVEL entries: {invalid_entries:?}"); + warn!("Ignoring invalid DD_LOG_LEVEL_BY_TARGET entries: {invalid_entries:?}"); } debug!("Logging subsystem enabled"); } -/// Builds the log filter from `DD_LOG_LEVEL`: a level such as `debug`, or comma-separated -/// directives in the `RUST_LOG` syntax, such as `info,cold_start_duration=debug`. The default -/// level is info. A directive with no level turns on all levels for its target. Returns the -/// entries that do not parse, so that a typo is logged instead of failing startup. -fn build_env_filter(log_level: &str) -> (EnvFilter, Vec) { - let mut env_filter = EnvFilter::try_new( - "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,info", - ) - .expect("could not parse default log filter"); +/// Builds the log filter from `DD_LOG_LEVEL` and `DD_LOG_LEVEL_BY_TARGET`, a comma-separated +/// list of `target=level` entries in the `RUST_LOG` syntax. An entry with no level turns on all +/// levels for that target. Targets include the module paths of dependencies, which use +/// underscores, such as `dogstatsd` or `datadog_agent_config`. Returns the entries that do not +/// parse, so that a typo is logged instead of failing startup. +fn build_env_filter(log_level: LogLevel, levels_by_target: &str) -> (EnvFilter, Vec) { + let mut env_filter = EnvFilter::try_new(format!( + "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}", + )) + .expect("could not parse log level in configuration"); let mut invalid_entries = Vec::new(); - for entry in log_level + for entry in levels_by_target .split(',') .map(str::trim) .filter(|e| !e.is_empty()) @@ -1632,52 +1643,36 @@ mod dsm_config_tests { #[cfg(test)] mod env_filter_tests { - use super::build_env_filter; - - fn directives(log_level: &str) -> (Vec, Vec) { - let (filter, invalid) = build_env_filter(log_level); - let directives = filter.to_string().split(',').map(String::from).collect(); - (directives, invalid) - } - - #[test] - fn defaults_to_info() { - let (directives, invalid) = directives(""); - assert!(directives.contains(&"info".to_string())); - assert!(invalid.is_empty()); - } - - #[test] - fn plain_level_replaces_default() { - let (directives, _) = directives("DEBUG"); - assert!(directives.contains(&"debug".to_string())); - assert!(!directives.contains(&"info".to_string())); - } + use super::{LogLevel, build_env_filter}; #[test] fn adds_directive_per_entry() { - let (directives, invalid) = - directives(" warn, cold_start_duration=debug, trace_flush_duration ,"); - assert!(directives.contains(&"warn".to_string())); - assert!(directives.contains(&"cold_start_duration=debug".to_string())); - assert!(directives.contains(&"trace_flush_duration=trace".to_string())); + let (filter, invalid) = build_env_filter( + LogLevel::Info, + " cold_start_duration=debug, trace_flush_duration ,", + ); + let filter = filter.to_string(); + assert!(filter.contains("cold_start_duration=debug")); + assert!(filter.contains("trace_flush_duration=trace")); assert!(invalid.is_empty()); } #[test] fn skips_invalid_entries() { - let (directives, invalid) = - directives("cold_start_duration=verbose,trace_flush_duration=debug"); - assert!(directives.contains(&"info".to_string())); - assert!(directives.contains(&"trace_flush_duration=debug".to_string())); + let (filter, invalid) = build_env_filter( + LogLevel::Info, + "cold_start_duration=verbose,trace_flush_duration=debug", + ); + assert!(filter.to_string().contains("trace_flush_duration=debug")); assert_eq!(invalid, vec!["cold_start_duration=verbose"]); } #[test] - fn overrides_default_target_levels() { - let (directives, _) = directives("debug,bottlecap::logs=warn,h2=debug"); - assert!(directives.contains(&"bottlecap::logs=warn".to_string())); - assert!(directives.contains(&"h2=debug".to_string())); - assert!(!directives.contains(&"h2=off".to_string())); + fn overrides_default_levels() { + let (filter, _) = build_env_filter(LogLevel::Debug, "bottlecap::logs=warn,h2=debug"); + let filter = filter.to_string(); + assert!(filter.contains("bottlecap::logs=warn")); + assert!(filter.contains("h2=debug")); + assert!(!filter.contains("h2=off")); } } diff --git a/bottlecap/src/logger.rs b/bottlecap/src/logger.rs index d36347d44..45d33c79a 100644 --- a/bottlecap/src/logger.rs +++ b/bottlecap/src/logger.rs @@ -6,11 +6,11 @@ use tracing_subscriber::fmt::{ }; use tracing_subscriber::registry::LookupSpan; -// `DD_LOG_LEVEL` matches a target by text prefix, so no target name may start with +// `DD_LOG_LEVEL_BY_TARGET` matches a target by text prefix, so no target name may start with // another one: an entry for `trace_flush` would also match `trace_flush_duration`. /// Tracing target for the duration of each cold start step. Enable it alone with -/// `DD_LOG_LEVEL=info,cold_start_duration=debug`. +/// `DD_LOG_LEVEL_BY_TARGET=cold_start_duration=debug`. pub const COLD_START_DURATION: &str = "cold_start_duration"; /// Logs at debug level how long `step` took since `start`, under a duration target such as From 6f1eab73e2378b588221a036bd7b788f6f5ffd16 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:09:07 -0400 Subject: [PATCH 10/14] [SVLS-9883] Accept only target=level entries in DD_LOG_LEVEL_BY_TARGET Each entry must be a target, `=`, and a level name. A level with no target, such as `debug`, used to replace DD_LOG_LEVEL, and a target with no level or a span filter such as `[span]` was also accepted. These are now invalid entries, which the extension logs as a warning and skips. Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/bin/bottlecap/main.rs | 50 ++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 092bc0cd3..7571223cc 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -263,10 +263,9 @@ fn enable_logging_subsystem() { } /// Builds the log filter from `DD_LOG_LEVEL` and `DD_LOG_LEVEL_BY_TARGET`, a comma-separated -/// list of `target=level` entries in the `RUST_LOG` syntax. An entry with no level turns on all -/// levels for that target. Targets include the module paths of dependencies, which use -/// underscores, such as `dogstatsd` or `datadog_agent_config`. Returns the entries that do not -/// parse, so that a typo is logged instead of failing startup. +/// list of `target=level` entries. Targets include the module paths of dependencies, which use +/// underscores, such as `dogstatsd` or `datadog_agent_config`. Returns the entries that are not +/// valid, so that a typo is logged instead of failing startup. fn build_env_filter(log_level: LogLevel, levels_by_target: &str) -> (EnvFilter, Vec) { let mut env_filter = EnvFilter::try_new(format!( "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}", @@ -278,14 +277,31 @@ fn build_env_filter(log_level: LogLevel, levels_by_target: &str) -> (EnvFilter, .map(str::trim) .filter(|e| !e.is_empty()) { - match entry.parse::() { - Ok(directive) => env_filter = env_filter.add_directive(directive), - Err(_) => invalid_entries.push(entry.to_string()), + match parse_target_level(entry) { + Some(directive) => env_filter = env_filter.add_directive(directive), + None => invalid_entries.push(entry.to_string()), } } (env_filter, invalid_entries) } +/// Parses one `target=level` entry. Rejects the other forms that `EnvFilter` accepts, such as a +/// level with no target, which would replace `DD_LOG_LEVEL`, or a span filter such as `[span]`. +fn parse_target_level(entry: &str) -> Option { + let (target, level) = entry.split_once('=')?; + let (target, level) = (target.trim(), level.trim()); + let valid_target = + !target.is_empty() && !target.contains(|c: char| c.is_whitespace() || "[]{}".contains(c)); + let valid_level = matches!( + level.to_ascii_lowercase().as_str(), + "off" | "error" | "warn" | "info" | "debug" | "trace" + ); + if !(valid_target && valid_level) { + return None; + } + format!("{target}={level}").parse().ok() +} + /// Returns the appropriate flush strategy for the given mode. /// In managed instance mode, continuous flush strategy is required for optimal performance. /// If a different strategy is configured, this function will override it and log an info message. @@ -1649,7 +1665,7 @@ mod env_filter_tests { fn adds_directive_per_entry() { let (filter, invalid) = build_env_filter( LogLevel::Info, - " cold_start_duration=debug, trace_flush_duration ,", + " cold_start_duration=debug, trace_flush_duration = TRACE ,", ); let filter = filter.to_string(); assert!(filter.contains("cold_start_duration=debug")); @@ -1661,10 +1677,22 @@ mod env_filter_tests { fn skips_invalid_entries() { let (filter, invalid) = build_env_filter( LogLevel::Info, - "cold_start_duration=verbose,trace_flush_duration=debug", + "debug,cold_start_duration,cold_start_duration=verbose,=debug,[span]=debug,a b=debug,trace_flush_duration=debug", + ); + let filter = filter.to_string(); + assert!(filter.contains("trace_flush_duration=debug")); + assert!(filter.ends_with(",info") || filter.contains(",info,")); + assert_eq!( + invalid, + vec![ + "debug", + "cold_start_duration", + "cold_start_duration=verbose", + "=debug", + "[span]=debug", + "a b=debug", + ] ); - assert!(filter.to_string().contains("trace_flush_duration=debug")); - assert_eq!(invalid, vec!["cold_start_duration=verbose"]); } #[test] From e47df3cbd56a6e87135b5c8eb6ce38b4374f0ec2 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Fri, 9 Oct 2026 14:36:05 -0400 Subject: [PATCH 11/14] [SVLS-9883] Use datadog-serverless-logging for DD_LOG_LEVEL_BY_TARGET The parsing and the variable name move to the new crate in serverless-components (DataDog/serverless-components#180), so that other serverless agents can share them. Points all five serverless-components dependencies at the head of #180. Its other changes since the current revision are docs and a lock file bump that the extension does not use. Co-Authored-By: Claude Opus 5.5 --- bottlecap/Cargo.lock | 17 +++-- bottlecap/Cargo.toml | 9 +-- bottlecap/LICENSE-3rdparty.csv | 1 + bottlecap/src/bin/bottlecap/main.rs | 101 +++------------------------- 4 files changed, 27 insertions(+), 101 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 61b5cf23d..60ff4a884 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -501,6 +501,7 @@ dependencies = [ "datadog-fips", "datadog-opentelemetry", "datadog-protos", + "datadog-serverless-logging", "ddsketch-agent", "dogstatsd", "figment", @@ -868,7 +869,7 @@ dependencies = [ [[package]] name = "datadog-agent-config" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" dependencies = [ "datadog-opentelemetry", "dogstatsd", @@ -886,12 +887,12 @@ dependencies = [ [[package]] name = "datadog-agent-trace-sampler" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" dependencies = [ "reqwest", "rustls", @@ -951,6 +952,14 @@ dependencies = [ "tonic-build", ] +[[package]] +name = "datadog-serverless-logging" +version = "0.1.0" +source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" +dependencies = [ + "tracing-subscriber", +] + [[package]] name = "ddsketch-agent" version = "0.1.0" @@ -1070,7 +1079,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=8156757470d0843a99fc5d19809ae021cd2c7178#8156757470d0843a99fc5d19809ae021cd2c7178" +source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" dependencies = [ "datadog-protos", "ddsketch-agent", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 07b8f8e0b..70d6141b7 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -95,10 +95,11 @@ libdd-trace-normalization = "3.0.1" libdd-trace-obfuscation = { version = "6.0.0", default-features = false } libdd-trace-stats = { version = "7.0.0", default-features = false } datadog-opentelemetry = { version = "0.5.2", default-features = false, features = ["_unstable_propagation"] } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } -datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } -datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "8156757470d0843a99fc5d19809ae021cd2c7178", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } +datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } +datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } +datadog-serverless-logging = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] diff --git a/bottlecap/LICENSE-3rdparty.csv b/bottlecap/LICENSE-3rdparty.csv index 45e5832de..3f02c8629 100644 --- a/bottlecap/LICENSE-3rdparty.csv +++ b/bottlecap/LICENSE-3rdparty.csv @@ -52,6 +52,7 @@ datadog-agent-trace-sampler,https://github.com/DataDog/serverless-components,Apa datadog-fips,https://github.com/DataDog/serverless-components,Apache-2.0,The datadog-fips Authors datadog-opentelemetry,https://github.com/DataDog/dd-trace-rs/tree/main/datadog-opentelemetry,Apache-2.0,Datadog Inc. datadog-protos,https://github.com/DataDog/saluki,Apache-2.0,The datadog-protos Authors +datadog-serverless-logging,https://github.com/DataDog/serverless-components,Apache-2.0,The datadog-serverless-logging Authors ddsketch-agent,https://github.com/DataDog/saluki,Apache-2.0,The ddsketch-agent Authors defmt,https://github.com/knurling-rs/defmt,MIT OR Apache-2.0,The Knurling-rs developers defmt-macros,https://github.com/knurling-rs/defmt,MIT OR Apache-2.0,The Knurling-rs developers diff --git a/bottlecap/src/bin/bottlecap/main.rs b/bottlecap/src/bin/bottlecap/main.rs index 7571223cc..81c47d3fd 100644 --- a/bottlecap/src/bin/bottlecap/main.rs +++ b/bottlecap/src/bin/bottlecap/main.rs @@ -81,6 +81,7 @@ use bottlecap::{ }, }; use datadog_fips::reqwest_adapter::create_reqwest_client_builder; +use datadog_serverless_logging::{LEVEL_BY_TARGET_ENV_VAR, build_env_filter}; use decrypt::{resolve_additional_endpoints_secrets, resolve_secrets}; use dogstatsd::{ aggregator::{ @@ -103,7 +104,6 @@ use tokio::time::Instant; use tokio::{sync::Mutex as TokioMutex, sync::mpsc::Sender}; use tokio_util::sync::CancellationToken; use tracing::{debug, error, warn}; -use tracing_subscriber::{EnvFilter, filter::Directive}; use ustr::Ustr; fn resolve_dsm_service( @@ -240,9 +240,12 @@ fn enable_logging_subsystem() { .unwrap_or(LogLevel::Info); let (env_filter, invalid_entries) = build_env_filter( - log_level, - &std::env::var("DD_LOG_LEVEL_BY_TARGET").unwrap_or_default(), - ); + &format!( + "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}" + ), + &std::env::var(LEVEL_BY_TARGET_ENV_VAR).unwrap_or_default(), + ) + .expect("could not parse log level in configuration"); let subscriber = tracing_subscriber::fmt::Subscriber::builder() .with_env_filter(env_filter) .with_level(true) @@ -257,51 +260,11 @@ fn enable_logging_subsystem() { tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); if !invalid_entries.is_empty() { - warn!("Ignoring invalid DD_LOG_LEVEL_BY_TARGET entries: {invalid_entries:?}"); + warn!("Ignoring invalid {LEVEL_BY_TARGET_ENV_VAR} entries: {invalid_entries:?}"); } debug!("Logging subsystem enabled"); } -/// Builds the log filter from `DD_LOG_LEVEL` and `DD_LOG_LEVEL_BY_TARGET`, a comma-separated -/// list of `target=level` entries. Targets include the module paths of dependencies, which use -/// underscores, such as `dogstatsd` or `datadog_agent_config`. Returns the entries that are not -/// valid, so that a typo is logged instead of failing startup. -fn build_env_filter(log_level: LogLevel, levels_by_target: &str) -> (EnvFilter, Vec) { - let mut env_filter = EnvFilter::try_new(format!( - "h2=off,hyper=off,reqwest=off,rustls=off,datadog-trace-mini-agent=off,{log_level:?}", - )) - .expect("could not parse log level in configuration"); - let mut invalid_entries = Vec::new(); - for entry in levels_by_target - .split(',') - .map(str::trim) - .filter(|e| !e.is_empty()) - { - match parse_target_level(entry) { - Some(directive) => env_filter = env_filter.add_directive(directive), - None => invalid_entries.push(entry.to_string()), - } - } - (env_filter, invalid_entries) -} - -/// Parses one `target=level` entry. Rejects the other forms that `EnvFilter` accepts, such as a -/// level with no target, which would replace `DD_LOG_LEVEL`, or a span filter such as `[span]`. -fn parse_target_level(entry: &str) -> Option { - let (target, level) = entry.split_once('=')?; - let (target, level) = (target.trim(), level.trim()); - let valid_target = - !target.is_empty() && !target.contains(|c: char| c.is_whitespace() || "[]{}".contains(c)); - let valid_level = matches!( - level.to_ascii_lowercase().as_str(), - "off" | "error" | "warn" | "info" | "debug" | "trace" - ); - if !(valid_target && valid_level) { - return None; - } - format!("{target}={level}").parse().ok() -} - /// Returns the appropriate flush strategy for the given mode. /// In managed instance mode, continuous flush strategy is required for optimal performance. /// If a different strategy is configured, this function will override it and log an info message. @@ -1656,51 +1619,3 @@ mod dsm_config_tests { assert_eq!(resolve_dsm_service(None, None), "aws.lambda"); } } - -#[cfg(test)] -mod env_filter_tests { - use super::{LogLevel, build_env_filter}; - - #[test] - fn adds_directive_per_entry() { - let (filter, invalid) = build_env_filter( - LogLevel::Info, - " cold_start_duration=debug, trace_flush_duration = TRACE ,", - ); - let filter = filter.to_string(); - assert!(filter.contains("cold_start_duration=debug")); - assert!(filter.contains("trace_flush_duration=trace")); - assert!(invalid.is_empty()); - } - - #[test] - fn skips_invalid_entries() { - let (filter, invalid) = build_env_filter( - LogLevel::Info, - "debug,cold_start_duration,cold_start_duration=verbose,=debug,[span]=debug,a b=debug,trace_flush_duration=debug", - ); - let filter = filter.to_string(); - assert!(filter.contains("trace_flush_duration=debug")); - assert!(filter.ends_with(",info") || filter.contains(",info,")); - assert_eq!( - invalid, - vec![ - "debug", - "cold_start_duration", - "cold_start_duration=verbose", - "=debug", - "[span]=debug", - "a b=debug", - ] - ); - } - - #[test] - fn overrides_default_levels() { - let (filter, _) = build_env_filter(LogLevel::Debug, "bottlecap::logs=warn,h2=debug"); - let filter = filter.to_string(); - assert!(filter.contains("bottlecap::logs=warn")); - assert!(filter.contains("h2=debug")); - assert!(!filter.contains("h2=off")); - } -} From c2aa611dbf21cb48b72594f2751913e0af51e62a Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Fri, 9 Oct 2026 15:09:16 -0400 Subject: [PATCH 12/14] [SVLS-9883] Drop the DD_LOG_LEVEL_BY_TARGET notes from the target constant The crate README of datadog-serverless-logging documents how to set the variable and the prefix match. Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/logger.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bottlecap/src/logger.rs b/bottlecap/src/logger.rs index 45d33c79a..1752e2f97 100644 --- a/bottlecap/src/logger.rs +++ b/bottlecap/src/logger.rs @@ -6,11 +6,7 @@ use tracing_subscriber::fmt::{ }; use tracing_subscriber::registry::LookupSpan; -// `DD_LOG_LEVEL_BY_TARGET` matches a target by text prefix, so no target name may start with -// another one: an entry for `trace_flush` would also match `trace_flush_duration`. - -/// Tracing target for the duration of each cold start step. Enable it alone with -/// `DD_LOG_LEVEL_BY_TARGET=cold_start_duration=debug`. +/// Tracing target for the duration of each cold start step. pub const COLD_START_DURATION: &str = "cold_start_duration"; /// Logs at debug level how long `step` took since `start`, under a duration target such as From f9fd99aa36972eaacd933da1291f6c78241cb3e0 Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Tue, 13 Oct 2026 12:43:38 -0400 Subject: [PATCH 13/14] [SVLS-9883] Bump serverless-components to the merge commit of #180 The merge commit has the same tree as the branch head that this PR used before, so the code does not change. Co-Authored-By: Claude Opus 5.5 --- bottlecap/Cargo.lock | 10 +++++----- bottlecap/Cargo.toml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bottlecap/Cargo.lock b/bottlecap/Cargo.lock index 60ff4a884..3aff1591e 100644 --- a/bottlecap/Cargo.lock +++ b/bottlecap/Cargo.lock @@ -869,7 +869,7 @@ dependencies = [ [[package]] name = "datadog-agent-config" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" +source = "git+https://github.com/DataDog/serverless-components?rev=9538fc7f08811e8912a7ce32c2ee7b887f90e9e2#9538fc7f08811e8912a7ce32c2ee7b887f90e9e2" dependencies = [ "datadog-opentelemetry", "dogstatsd", @@ -887,12 +887,12 @@ dependencies = [ [[package]] name = "datadog-agent-trace-sampler" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" +source = "git+https://github.com/DataDog/serverless-components?rev=9538fc7f08811e8912a7ce32c2ee7b887f90e9e2#9538fc7f08811e8912a7ce32c2ee7b887f90e9e2" [[package]] name = "datadog-fips" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" +source = "git+https://github.com/DataDog/serverless-components?rev=9538fc7f08811e8912a7ce32c2ee7b887f90e9e2#9538fc7f08811e8912a7ce32c2ee7b887f90e9e2" dependencies = [ "reqwest", "rustls", @@ -955,7 +955,7 @@ dependencies = [ [[package]] name = "datadog-serverless-logging" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" +source = "git+https://github.com/DataDog/serverless-components?rev=9538fc7f08811e8912a7ce32c2ee7b887f90e9e2#9538fc7f08811e8912a7ce32c2ee7b887f90e9e2" dependencies = [ "tracing-subscriber", ] @@ -1079,7 +1079,7 @@ dependencies = [ [[package]] name = "dogstatsd" version = "0.1.0" -source = "git+https://github.com/DataDog/serverless-components?rev=e5524046ed1184b32de656e3a86eed91976180f8#e5524046ed1184b32de656e3a86eed91976180f8" +source = "git+https://github.com/DataDog/serverless-components?rev=9538fc7f08811e8912a7ce32c2ee7b887f90e9e2#9538fc7f08811e8912a7ce32c2ee7b887f90e9e2" dependencies = [ "datadog-protos", "ddsketch-agent", diff --git a/bottlecap/Cargo.toml b/bottlecap/Cargo.toml index 70d6141b7..a6e7bf973 100644 --- a/bottlecap/Cargo.toml +++ b/bottlecap/Cargo.toml @@ -95,11 +95,11 @@ libdd-trace-normalization = "3.0.1" libdd-trace-obfuscation = { version = "6.0.0", default-features = false } libdd-trace-stats = { version = "7.0.0", default-features = false } datadog-opentelemetry = { version = "0.5.2", default-features = false, features = ["_unstable_propagation"] } -dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } -datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } -datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } -datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } -datadog-serverless-logging = { git = "https://github.com/DataDog/serverless-components", rev = "e5524046ed1184b32de656e3a86eed91976180f8", default-features = false } +dogstatsd = { git = "https://github.com/DataDog/serverless-components", rev = "9538fc7f08811e8912a7ce32c2ee7b887f90e9e2", default-features = false } +datadog-fips = { git = "https://github.com/DataDog/serverless-components", rev = "9538fc7f08811e8912a7ce32c2ee7b887f90e9e2", default-features = false } +datadog-agent-config = { git = "https://github.com/DataDog/serverless-components", rev = "9538fc7f08811e8912a7ce32c2ee7b887f90e9e2", default-features = false } +datadog-agent-trace-sampler = { git = "https://github.com/DataDog/serverless-components", rev = "9538fc7f08811e8912a7ce32c2ee7b887f90e9e2", default-features = false } +datadog-serverless-logging = { git = "https://github.com/DataDog/serverless-components", rev = "9538fc7f08811e8912a7ce32c2ee7b887f90e9e2", default-features = false } libddwaf = { version = "1.28.1", git = "https://github.com/DataDog/libddwaf-rust", rev = "d1534a158d976bd4f747bf9fcc58e0712d2d17fc", default-features = false, features = ["serde"] } [dev-dependencies] From fcb610e1b7f4abd45502a1940a252413848ff09c Mon Sep 17 00:00:00 2001 From: lym953 <10097700+lym953@users.noreply.github.com> Date: Wed, 14 Oct 2026 15:12:10 -0400 Subject: [PATCH 14/14] [SVLS-9883] Bring back the note about target names next to the target constant A DD_LOG_LEVEL_BY_TARGET entry matches every target that starts with its text. The next target is added in logger.rs, so the warning belongs there, not only in the serverless-components README. Co-Authored-By: Claude Opus 5.5 --- bottlecap/src/logger.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bottlecap/src/logger.rs b/bottlecap/src/logger.rs index 1752e2f97..8acf8ce50 100644 --- a/bottlecap/src/logger.rs +++ b/bottlecap/src/logger.rs @@ -6,6 +6,9 @@ use tracing_subscriber::fmt::{ }; use tracing_subscriber::registry::LookupSpan; +// `DD_LOG_LEVEL_BY_TARGET` matches a target by text prefix, so no target name may start with +// another one: an entry for `trace_flush` would also match `trace_flush_duration`. + /// Tracing target for the duration of each cold start step. pub const COLD_START_DURATION: &str = "cold_start_duration";