use std::borrow::Cow; use serde::Serialize; #[derive(Clone, Debug)] pub struct BackendConfig { pub dsn: Option, pub environment: Option, pub release: Option, pub send_default_pii: bool, } #[derive(Clone, Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct FrontendConfig { pub dsn: String, #[serde(skip_serializing_if = "Option::is_none")] pub environment: Option, #[serde(skip_serializing_if = "Option::is_none")] pub release: Option, pub send_default_pii: bool, } pub fn env_nonempty(name: &str) -> Option { std::env::var(name).ok().and_then(nonempty) } pub fn nonempty(value: String) -> Option { let trimmed = value.trim(); (!trimmed.is_empty()).then(|| trimmed.to_owned()) } pub fn default_release() -> String { format!("{}@{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")) } pub fn init_backend(config: &BackendConfig) -> Option { let dsn = config.dsn.clone().and_then(nonempty)?; let dsn = match dsn.parse::() { Ok(dsn) => dsn, Err(err) => { eprintln!("Ignoring invalid BUGSINK_DSN: {err}"); return None; } }; Some(sentry::init(sentry::ClientOptions { dsn: Some(dsn), environment: config .environment .clone() .and_then(nonempty) .map(Cow::Owned), release: Some(Cow::Owned( config .release .clone() .and_then(nonempty) .unwrap_or_else(default_release), )), send_default_pii: config.send_default_pii, traces_sample_rate: 0.0, ..Default::default() })) } pub fn frontend_config( dsn: Option, environment: Option, release: Option, send_default_pii: bool, ) -> Option { dsn.and_then(nonempty).map(|dsn| FrontendConfig { dsn, environment: environment.and_then(nonempty), release: release.and_then(nonempty), send_default_pii, }) }