mirror of
https://github.com/block/goose.git
synced 2026-07-17 12:56:20 +02:00
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:
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user