@@ -79,7 +79,7 @@ pub struct PhpSpanStats<'a> {
7979}
8080
8181#[ inline]
82- fn char_slice_str ( s : CharSlice ) -> & str {
82+ fn char_slice_str ( s : CharSlice < ' _ > ) -> & str {
8383 s. try_to_utf8 ( ) . unwrap_or ( "" )
8484}
8585
@@ -232,6 +232,19 @@ static SPAN_CONCENTRATORS: LazyLock<RwLock<HashMap<String, SpanConcentrator>>> =
232232/// i.e. the sidecar has received and applied the agent's /info response.
233233static AGENT_INFO_RECEIVED : AtomicBool = AtomicBool :: new ( false ) ;
234234
235+ /// Set to true once agent info confirms `client_drop_p0s` is true and the
236+ /// reported agent version is >= 7.65.0. Cached so the per-span hot-path is a
237+ /// single atomic load.
238+ static STATS_COMPUTATION_READY : AtomicBool = AtomicBool :: new ( false ) ;
239+
240+ fn agent_version_ge ( version : Option < & str > , req_major : u32 , req_minor : u32 , req_patch : u32 ) -> bool {
241+ let Some ( v) = version else { return false ; } ;
242+ let v = v. split ( '-' ) . next ( ) . unwrap_or ( v) ; // strip agent version suffixes
243+ let mut parts = v. split ( '.' ) . filter_map ( |p| p. parse :: < u32 > ( ) . ok ( ) ) ;
244+ let ( Some ( major) , Some ( minor) , Some ( patch) ) = ( parts. next ( ) , parts. next ( ) , parts. next ( ) ) else { return false ; } ;
245+ ( major, minor, patch) >= ( req_major, req_minor, req_patch)
246+ }
247+
235248/// Returns true once the agent /info has been received and applied.
236249/// Used by the PHP extension to skip stats computation until the concentrator
237250/// has been properly initialised with peer-tag keys and span kinds.
@@ -240,6 +253,14 @@ pub extern "C" fn ddog_is_agent_info_ready() -> bool {
240253 AGENT_INFO_RECEIVED . load ( Ordering :: Acquire )
241254}
242255
256+ /// Returns true when the agent supports client-side stats computation:
257+ /// agent info has been received, `client_drop_p0s` is true, and the reported
258+ /// agent version is >= 7.65.0.
259+ #[ no_mangle]
260+ pub extern "C" fn ddog_agent_has_stats_computation ( ) -> bool {
261+ STATS_COMPUTATION_READY . load ( Ordering :: Acquire )
262+ }
263+
243264/// Desired concentrator configuration sourced from the agent's /info endpoint.
244265/// Populated via `ddog_apply_agent_info`; applied to every concentrator
245266/// at creation time and when the config changes.
@@ -253,6 +274,7 @@ static DESIRED_CONFIG: LazyLock<RwLock<DesiredConfig>> = LazyLock::new(|| RwLock
253274
254275/// Apply updated concentrator config (peer-tag keys, span kinds, trace filters) to
255276/// `DESIRED_CONFIG` and propagate peer-tag / span-kind changes to all open concentrators.
277+ /// Also updates the `STATS_COMPUTATION_READY` flag based on `client_drop_p0s` and `version`.
256278pub ( crate ) fn apply_concentrator_config (
257279 peer_tag_keys : Vec < String > ,
258280 span_kinds : Vec < String > ,
@@ -261,12 +283,16 @@ pub(crate) fn apply_concentrator_config(
261283 regex_require : Vec < String > ,
262284 regex_reject : Vec < String > ,
263285 ignore_resources : Vec < String > ,
286+ client_drop_p0s : bool ,
287+ version : Option < & str > ,
264288) {
265289 let compiled = trace_filter:: compile_trace_filter (
266290 & tags_require, & tags_reject, & regex_require, & regex_reject, & ignore_resources,
267291 ) ;
268292 trace_filter:: set_trace_filter ( compiled) ;
269293 AGENT_INFO_RECEIVED . store ( true , Ordering :: Release ) ;
294+ let ready = client_drop_p0s && agent_version_ge ( version, 7 , 65 , 0 ) ;
295+ STATS_COMPUTATION_READY . store ( ready, Ordering :: Release ) ;
270296 {
271297 let mut dc = DESIRED_CONFIG . write ( ) . unwrap ( ) ;
272298 dc. peer_tag_keys = peer_tag_keys. clone ( ) ;
0 commit comments