Update telemetry consent in memory on config change

Replace the TTL-based cache with a Lazy<AtomicBool> that is
initialised once from config and updated immediately via
set_telemetry_enabled() whenever the telemetry key is written
through the /config/upsert, /config/remove, or CLI configure paths.

This gives hot paths (Sentry before_send / traces_sampler) zero
disk I/O while ensuring opt-in and opt-out take effect instantly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jh-block
2026-03-05 15:09:58 -05:00
parent c93927146c
commit f499e1a00a
3 changed files with 29 additions and 29 deletions
@@ -94,6 +94,7 @@ pub fn configure_telemetry_consent_dialog() -> anyhow::Result<bool> {
.interact()?;
config.set_param(TELEMETRY_ENABLED_KEY, enabled)?;
goose::posthog::set_telemetry_enabled(enabled);
if enabled {
let _ = cliclack::log::success("Thank you for helping improve goose!");
@@ -1383,6 +1384,7 @@ pub fn configure_telemetry_dialog() -> anyhow::Result<()> {
.interact()?;
config.set_param(TELEMETRY_ENABLED_KEY, enabled)?;
goose::posthog::set_telemetry_enabled(enabled);
if enabled {
cliclack::outro("Telemetry enabled - thank you for helping improve goose!")?;
@@ -173,6 +173,12 @@ pub async fn upsert_config(
) -> Result<Json<Value>, ErrorResponse> {
let config = Config::global();
config.set(&query.key, &query.value, query.is_secret)?;
if query.key == goose::posthog::TELEMETRY_ENABLED_KEY {
let enabled = query.value.as_bool().unwrap_or(false);
goose::posthog::set_telemetry_enabled(enabled);
}
Ok(Json(Value::String(format!("Upserted key {}", query.key))))
}
@@ -197,6 +203,10 @@ pub async fn remove_config(
config.delete(&query.key)?;
}
if query.key == goose::posthog::TELEMETRY_ENABLED_KEY {
goose::posthog::set_telemetry_enabled(false);
}
Ok(Json(format!("Removed key {}", query.key)))
}
+17 -29
View File
@@ -10,9 +10,8 @@ use chrono::{DateTime, Utc};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use std::fs;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;
const POSTHOG_API_KEY: &str = "phc_RyX5CaY01VtZJCQyhSR5KFh6qimUy81YwxsEpotAftT";
@@ -41,38 +40,27 @@ pub fn get_telemetry_choice() -> Option<bool> {
config.get_param::<bool>(TELEMETRY_ENABLED_KEY).ok()
}
// Cached result of the telemetry consent check so that hot paths
// (e.g. Sentry traces_sampler) avoid disk I/O on every call.
static TELEMETRY_CACHE: AtomicBool = AtomicBool::new(false);
static TELEMETRY_CACHE_TIME: AtomicU64 = AtomicU64::new(0);
const TELEMETRY_CACHE_TTL_SECS: u64 = 5;
// In-memory telemetry consent flag. Initialised from config on first
// access and updated immediately via `set_telemetry_enabled()` when the
// config changes, so hot paths (Sentry callbacks) never hit disk.
static TELEMETRY_ENABLED: Lazy<AtomicBool> = Lazy::new(|| {
AtomicBool::new(get_telemetry_choice().unwrap_or(false))
});
/// Check if telemetry is enabled.
///
/// Returns false if:
/// - GOOSE_TELEMETRY_OFF environment variable is set to "1" or "true"
/// - GOOSE_TELEMETRY_ENABLED config value is set to false
/// - User has not made a telemetry choice yet (opt-in required)
/// Check if telemetry is enabled (fast, no disk I/O).
///
/// Returns true only if the user has explicitly opted in.
///
/// The result is cached for up to 5 seconds to avoid repeated disk I/O
/// when called from high-frequency paths like Sentry's traces_sampler.
pub fn is_telemetry_enabled() -> bool {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
let last = TELEMETRY_CACHE_TIME.load(Ordering::Relaxed);
TELEMETRY_ENABLED.load(Ordering::Relaxed)
}
if now.saturating_sub(last) < TELEMETRY_CACHE_TTL_SECS {
return TELEMETRY_CACHE.load(Ordering::Relaxed);
}
let enabled = get_telemetry_choice().unwrap_or(false);
TELEMETRY_CACHE.store(enabled, Ordering::Relaxed);
TELEMETRY_CACHE_TIME.store(now, Ordering::Relaxed);
enabled
/// Update the in-memory telemetry consent flag.
///
/// Call this whenever the `GOOSE_TELEMETRY_ENABLED` config value is
/// changed so that Sentry callbacks and other hot paths see the new
/// state immediately.
pub fn set_telemetry_enabled(enabled: bool) {
TELEMETRY_ENABLED.store(enabled, Ordering::Relaxed);
}
// ============================================================================