use dotenv::dotenv;
use std::env;
use std::io::IsTerminal;
use tracing::warn;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use crate::utils::redis_client::initialize_global_redis_from_env;
const DEFAULT_TRACING_FILTER: &str = "info";
pub struct ProcessRuntimeGuard {
#[cfg(feature = "sentry")]
_sentry_guard: Option<sentry::ClientInitGuard>,
}
pub fn initialize_process_runtime() -> ProcessRuntimeGuard {
let dotenv_error = dotenv().err();
initialize_global_redis_from_env();
#[cfg(feature = "sentry")]
let sentry_guard = init_sentry();
init_tracing(
#[cfg(feature = "sentry")]
sentry_guard.is_some(),
#[cfg(not(feature = "sentry"))]
false,
);
if let Some(err) = dotenv_error {
warn!(
error = %err,
"Failed to parse `.env` in the current directory; variables from that file are skipped"
);
}
ProcessRuntimeGuard {
#[cfg(feature = "sentry")]
_sentry_guard: sentry_guard,
}
}
fn init_tracing(enable_sentry_layer: bool) {
let env_filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new(DEFAULT_TRACING_FILTER));
let fmt_layer = tracing_subscriber::fmt::layer()
.with_ansi(std::io::stderr().is_terminal())
.with_target(true);
#[cfg(feature = "sentry")]
{
let registry = tracing_subscriber::registry()
.with(env_filter)
.with(fmt_layer);
if enable_sentry_layer {
let _ = registry.with(sentry_tracing::layer()).try_init();
} else {
let _ = registry.try_init();
}
}
#[cfg(not(feature = "sentry"))]
{
let _ = tracing_subscriber::registry()
.with(env_filter)
.with(fmt_layer)
.try_init();
}
}
#[cfg(feature = "sentry")]
const BETTERSTACK_SENTRY_DSN: &str =
"https://mMR1Bs5K6vSzXT8YGYyUxQSE@s1741777.eu-fsn-3.betterstackdata.com/1741777";
#[cfg(feature = "sentry")]
fn init_sentry() -> Option<sentry::ClientInitGuard> {
let dsn_source = env::var("SENTRY_DSN").unwrap_or_else(|_| BETTERSTACK_SENTRY_DSN.to_string());
if dsn_source.trim().is_empty() {
return None;
}
let dsn = match dsn_source.parse::<sentry::types::Dsn>() {
Ok(dsn) => dsn,
Err(err) => {
eprintln!("failed to parse Sentry DSN: {err}");
return None;
}
};
let mut options = sentry::ClientOptions {
dsn: Some(dsn),
release: Some(env!("CARGO_PKG_VERSION").into()),
environment: env::var("SENTRY_ENVIRONMENT").ok().map(Into::into),
attach_stacktrace: true,
..Default::default()
};
if let Ok(value) = env::var("SENTRY_SAMPLE_RATE")
&& let Ok(parsed) = value.parse::<f32>()
{
options.sample_rate = parsed;
}
Some(sentry::init(options))
}