1use tracing_subscriber::layer::SubscriberExt;
9use tracing_subscriber::util::SubscriberInitExt;
10use tracing_subscriber::{fmt, EnvFilter};
11
12pub enum LogMode {
14 Cli,
16 Proxy,
18}
19
20#[cfg(feature = "sentry")]
24pub type SentryGuard = sentry::ClientInitGuard;
25#[cfg(not(feature = "sentry"))]
26pub type SentryGuard = ();
27
28pub fn init(mode: LogMode, verbose: bool) -> Option<SentryGuard> {
34 let filter = match std::env::var("RUST_LOG") {
35 Ok(val) if !val.is_empty() => EnvFilter::from_default_env(),
36 _ if verbose => EnvFilter::new("debug"),
37 _ => EnvFilter::new("info"),
38 };
39
40 let sentry_guard = init_sentry();
42
43 let registry = tracing_subscriber::registry().with(filter);
47
48 #[cfg(feature = "sentry")]
49 let registry = registry.with(sentry_guard.as_ref().map(|_| sentry_tracing::layer()));
50
51 match mode {
52 LogMode::Proxy => {
53 registry
54 .with(
55 fmt::layer()
56 .json()
57 .flatten_event(true)
58 .with_writer(std::io::stderr)
59 .with_target(true)
60 .with_current_span(false),
61 )
62 .init();
63 }
64 LogMode::Cli => {
65 registry
66 .with(
67 fmt::layer()
68 .compact()
69 .with_writer(std::io::stderr)
70 .with_target(false),
71 )
72 .init();
73 }
74 }
75
76 #[cfg(not(feature = "sentry"))]
78 if std::env::var("SENTRY_DSN").is_ok() || std::env::var("GREP_SENTRY_DSN").is_ok() {
79 tracing::warn!(
80 "SENTRY_DSN is set but this binary was compiled without the sentry feature — ignoring. \
81 Build with: cargo build --features sentry"
82 );
83 }
84
85 sentry_guard
86}
87
88#[cfg(feature = "sentry")]
92pub fn shutdown(guard: Option<SentryGuard>) {
93 drop(guard);
94}
95
96#[cfg(not(feature = "sentry"))]
97#[inline]
98pub fn shutdown(_guard: Option<SentryGuard>) {}
99
100fn init_sentry() -> Option<SentryGuard> {
103 #[cfg(feature = "sentry")]
104 {
105 let dsn = std::env::var("GREP_SENTRY_DSN")
106 .or_else(|_| std::env::var("SENTRY_DSN"))
107 .ok()?;
108
109 let environment =
110 std::env::var("ENVIRONMENT_TIER").unwrap_or_else(|_| "development".into());
111
112 match environment.as_str() {
114 "production" | "staging" | "demo" => {}
115 _ => {
116 tracing::debug!(environment = %environment, "sentry disabled for this environment");
117 return None;
118 }
119 }
120
121 let service = std::env::var("SERVICE_NAME").unwrap_or_else(|_| "ati-proxy".into());
122
123 let sample_rate = match environment.as_str() {
124 "production" => 0.25,
125 "staging" => 0.5,
126 _ => 1.0,
127 };
128
129 let sentry_debug = std::env::var("ATI_SENTRY_DEBUG")
130 .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
131 .unwrap_or(false);
132
133 let guard = sentry::init((
134 dsn,
135 sentry::ClientOptions {
136 release: Some(env!("CARGO_PKG_VERSION").into()),
137 environment: Some(environment.into()),
138 server_name: Some(service.into()),
139 traces_sample_rate: sample_rate,
140 attach_stacktrace: true,
141 send_default_pii: false,
142 debug: sentry_debug,
143 ..Default::default()
144 },
145 ));
146
147 if guard.is_enabled() {
148 Some(guard)
149 } else {
150 None
151 }
152 }
153
154 #[cfg(not(feature = "sentry"))]
155 {
156 None
157 }
158}