diff --git a/rust/connlib/socket-factory/src/lib.rs b/rust/connlib/socket-factory/src/lib.rs index 7d0d0f910..9189dc20d 100644 --- a/rust/connlib/socket-factory/src/lib.rs +++ b/rust/connlib/socket-factory/src/lib.rs @@ -356,6 +356,9 @@ impl UdpSocket { if e.raw_os_error().is_some_and(|e| e == libc::ENOBUFS) && firezone_telemetry::feature_flags::map_enobufs_to_would_block() => { + firezone_telemetry::analytics::feature_flag_called( + "map-enobufs-to-wouldblock", + ); tracing::debug!("Encountered ENOBUFS, treating as WouldBlock"); Err(io::Error::from(io::ErrorKind::WouldBlock)) diff --git a/rust/telemetry/src/analytics.rs b/rust/telemetry/src/analytics.rs index 1c165d037..f9c0bc280 100644 --- a/rust/telemetry/src/analytics.rs +++ b/rust/telemetry/src/analytics.rs @@ -65,6 +65,36 @@ pub fn identify(release: String, account_slug: Option) { }); } +pub fn feature_flag_called(name: impl Into) { + let Some(env) = Telemetry::current_env() else { + tracing::debug!("Cannot send $feature_flag_called: Unknown env"); + return; + }; + let Some(distinct_id) = Telemetry::current_user() else { + tracing::debug!("Cannot send $feature_flag_called: Unknown user"); + return; + }; + let feature_flag = name.into(); + + RUNTIME.spawn({ + async move { + if let Err(e) = capture( + "$feature_flag_called", + distinct_id, + env, + FeatureFlagCalledProperties { + feature_flag, + feature_flag_response: "true".to_owned(), + }, + ) + .await + { + tracing::debug!("Failed to log `$feature_flag_called` event: {e:#}"); + } + } + }); +} + async fn capture

( event: impl Into, distinct_id: String, @@ -137,3 +167,11 @@ struct PersonProperties { #[serde(rename = "$os")] os: String, } + +#[derive(serde::Serialize)] +struct FeatureFlagCalledProperties { + #[serde(rename = "$feature_flag")] + feature_flag: String, + #[serde(rename = "$feature_flag_response")] + feature_flag_response: String, +}