diff --git a/datadog-sidecar-ffi/src/lib.rs b/datadog-sidecar-ffi/src/lib.rs index 7cc6a3267d..d18dd943fd 100644 --- a/datadog-sidecar-ffi/src/lib.rs +++ b/datadog-sidecar-ffi/src/lib.rs @@ -723,6 +723,30 @@ pub unsafe extern "C" fn ddog_sidecar_session_set_process_tags( MaybeError::None } +/// Records the default service name for the session. Empty = user-defined +/// (sidecar emits `svc.user:true`); non-empty = auto-resolved with that name +/// (sidecar emits `svc.auto:`). +#[no_mangle] +#[allow(clippy::missing_safety_doc)] +pub unsafe extern "C" fn ddog_sidecar_session_set_default_service_name( + transport: &mut Box, + default_service_name: ffi::CharSlice, +) -> MaybeError { + let source = if default_service_name.is_empty() { + datadog_sidecar::service::ServiceNameSource::UserDefined + } else { + datadog_sidecar::service::ServiceNameSource::AutoResolved( + default_service_name.to_utf8_lossy().into_owned(), + ) + }; + try_c!(blocking::set_session_default_service_name( + transport, + Some(source), + )); + + MaybeError::None +} + #[repr(C)] pub struct TracerHeaderTags<'a> { pub lang: ffi::CharSlice<'a>, diff --git a/datadog-sidecar/src/service/blocking.rs b/datadog-sidecar/src/service/blocking.rs index 99b84af008..fb7c324d97 100644 --- a/datadog-sidecar/src/service/blocking.rs +++ b/datadog-sidecar/src/service/blocking.rs @@ -258,6 +258,14 @@ pub fn set_session_process_tags( Ok(()) } +pub fn set_session_default_service_name( + transport: &mut SidecarTransport, + service_name_source: Option, +) -> io::Result<()> { + lock_sender(transport)?.set_session_default_service_name(service_name_source); + Ok(()) +} + /// Sends a trace as bytes. pub fn send_trace_v04_bytes( transport: &mut SidecarTransport, diff --git a/datadog-sidecar/src/service/mod.rs b/datadog-sidecar/src/service/mod.rs index bc5930fc78..8810c20b44 100644 --- a/datadog-sidecar/src/service/mod.rs +++ b/datadog-sidecar/src/service/mod.rs @@ -83,3 +83,9 @@ pub enum SidecarAction { AddTelemetryMetricPoint((String, f64, Vec)), PhpComposerTelemetryFile(PathBuf), } + +#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] +pub enum ServiceNameSource { + UserDefined, + AutoResolved(String), +} diff --git a/datadog-sidecar/src/service/runtime_info.rs b/datadog-sidecar/src/service/runtime_info.rs index d05de803b3..5f40004049 100644 --- a/datadog-sidecar/src/service/runtime_info.rs +++ b/datadog-sidecar/src/service/runtime_info.rs @@ -142,7 +142,7 @@ impl ActiveApplication { .expect("Expecting remote config invariants to be set early") .clone(); - let process_tags = session.process_tags.lock_or_panic().clone(); + let process_tags = session.process_tags_with_svc_source(); if *session.remote_config_enabled.lock_or_panic() { self.remote_config_guard = Some( diff --git a/datadog-sidecar/src/service/sender.rs b/datadog-sidecar/src/service/sender.rs index f3bc672fd0..91b41ee183 100644 --- a/datadog-sidecar/src/service/sender.rs +++ b/datadog-sidecar/src/service/sender.rs @@ -35,6 +35,7 @@ use tracing::trace; struct SidecarOutbox { set_session_config: Option, set_session_process_tags: Option, + set_session_default_service_name: Option, set_universal_service_tags: Option, set_request_config: Option, clear_queue_id: Option, @@ -43,10 +44,11 @@ struct SidecarOutbox { } impl SidecarOutbox { - fn slots_mut(&mut self) -> [&mut Option; 7] { + fn slots_mut(&mut self) -> [&mut Option; 8] { [ &mut self.set_session_config, &mut self.set_session_process_tags, + &mut self.set_session_default_service_name, &mut self.set_universal_service_tags, &mut self.set_request_config, &mut self.clear_queue_id, @@ -122,6 +124,9 @@ fn coalesce(outbox: &mut SidecarOutbox, incoming: SidecarInterfaceRequest) { SidecarInterfaceRequest::SetSessionProcessTags { .. } => { outbox.set_session_process_tags = Some(incoming); } + SidecarInterfaceRequest::SetSessionDefaultServiceName { .. } => { + outbox.set_session_default_service_name = Some(incoming); + } SidecarInterfaceRequest::SetUniversalServiceTags { .. } => { outbox.set_universal_service_tags = Some(incoming); } @@ -236,6 +241,19 @@ impl SidecarSender { self.try_drain_outbox(); } + pub fn set_session_default_service_name( + &mut self, + service_name_source: Option, + ) { + coalesce( + &mut self.outbox, + SidecarInterfaceRequest::SetSessionDefaultServiceName { + service_name_source, + }, + ); + self.try_drain_outbox(); + } + #[allow(clippy::too_many_arguments)] pub fn set_universal_service_tags( &mut self, diff --git a/datadog-sidecar/src/service/session_info.rs b/datadog-sidecar/src/service/session_info.rs index efa0204715..dee6cec678 100644 --- a/datadog-sidecar/src/service/session_info.rs +++ b/datadog-sidecar/src/service/session_info.rs @@ -18,7 +18,7 @@ use libdd_common::{tag::Tag, MutexExt}; use tracing::{debug, error, info, trace, warn}; use crate::service::agent_info::AgentInfoGuard; -use crate::service::{InstanceId, QueueId, RuntimeInfo}; +use crate::service::{InstanceId, QueueId, RuntimeInfo, ServiceNameSource}; /// `SessionInfo` holds information about a session. /// @@ -45,6 +45,7 @@ pub(crate) struct SessionInfo { pub(crate) pid: Arc, pub(crate) remote_config_enabled: Arc>, pub(crate) process_tags: Arc>>, + pub(crate) service_name_source: Arc>>, pub(crate) stats_config: Arc>>, } @@ -130,6 +131,31 @@ impl SessionInfo { self.runtimes.lock_or_panic() } + pub(crate) fn process_tags_with_svc_source(&self) -> Vec { + let mut tags = self.process_tags.lock_or_panic().clone(); + if let Some(source) = self.service_name_source.lock_or_panic().as_ref() { + let (key, value) = match source { + ServiceNameSource::UserDefined => ("svc.user", "true".to_string()), + ServiceNameSource::AutoResolved(name) => ("svc.auto", name.clone()), + }; + if let Ok(tag) = Tag::new(key, value) { + tags.push(tag); + } + } + tags + } + + pub(crate) fn refresh_stats_process_tags(&self) { + if let Some(stats) = self.stats_config.lock_or_panic().as_mut() { + stats.process_tags = self + .process_tags_with_svc_source() + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(","); + } + } + pub(crate) fn get_telemetry_config( &self, ) -> MutexGuard<'_, Option> { diff --git a/datadog-sidecar/src/service/sidecar_interface.rs b/datadog-sidecar/src/service/sidecar_interface.rs index ff6313ba36..35406c7bad 100644 --- a/datadog-sidecar/src/service/sidecar_interface.rs +++ b/datadog-sidecar/src/service/sidecar_interface.rs @@ -69,6 +69,11 @@ pub trait SidecarInterface { /// * `process_tags` - The process tags. async fn set_session_process_tags(process_tags: Vec); + /// Records the source of the default service name for the session. + async fn set_session_default_service_name( + service_name_source: Option, + ); + /// Removes the application entry for the given queue ID from the instance. /// /// # Arguments diff --git a/datadog-sidecar/src/service/sidecar_server.rs b/datadog-sidecar/src/service/sidecar_server.rs index e4841081a6..45ee68f0ee 100644 --- a/datadog-sidecar/src/service/sidecar_server.rs +++ b/datadog-sidecar/src/service/sidecar_server.rs @@ -416,7 +416,7 @@ impl SidecarInterface for ConnectionSidecarHandler { .unwrap_or("unknown-service"); let env = entry.get().env.as_deref().unwrap_or("none"); - let process_tags = session.process_tags.lock_or_panic().clone(); + let process_tags = session.process_tags_with_svc_source(); // Pre-compute session config so both the primary and retry get_or_create calls // can use it without re-locking the session. @@ -697,8 +697,8 @@ impl SidecarInterface for ConnectionSidecarHandler { } else { config.hostname.clone() }, - process_tags: config - .process_tags + process_tags: session + .process_tags_with_svc_source() .iter() .map(|t| t.to_string()) .collect::>() @@ -762,6 +762,22 @@ impl SidecarInterface for ConnectionSidecarHandler { .unwrap_or_default(); let session = self.server.get_session(session_id); *session.process_tags.lock_or_panic() = process_tags; + session.refresh_stats_process_tags(); + } + + async fn set_session_default_service_name( + &self, + _peer: PeerCredentials, + service_name_source: Option, + ) { + let session_id = self + .session_id + .get() + .map(|s| s.as_str()) + .unwrap_or_default(); + let session = self.server.get_session(session_id); + *session.service_name_source.lock_or_panic() = service_name_source; + session.refresh_stats_process_tags(); } async fn shutdown_runtime(&self, _peer: PeerCredentials, instance_id: InstanceId) { diff --git a/datadog-sidecar/src/service/telemetry.rs b/datadog-sidecar/src/service/telemetry.rs index 201f72fb33..3896220f7d 100644 --- a/datadog-sidecar/src/service/telemetry.rs +++ b/datadog-sidecar/src/service/telemetry.rs @@ -701,7 +701,7 @@ fn get_telemetry_client( return None; }; - let process_tags = session.process_tags.lock_or_panic().clone(); + let process_tags = session.process_tags_with_svc_source(); Some(sidecar.telemetry_clients.get_or_create( service_name,