embeddenator_obs/obs/
tracing.rs1#[cfg(feature = "tracing")]
40use tracing::{span, Level, Span};
41
42#[cfg(feature = "tracing")]
51pub fn init_tracing() {
52 use tracing_subscriber::{fmt, EnvFilter};
53
54 let filter = std::env::var("EMBEDDENATOR_LOG")
55 .ok()
56 .or_else(|| std::env::var("RUST_LOG").ok())
57 .unwrap_or_else(|| "off".to_string());
58
59 let format = std::env::var("EMBEDDENATOR_TRACE_FORMAT")
60 .ok()
61 .unwrap_or_else(|| "compact".to_string());
62
63 let env_filter = EnvFilter::try_from_default_env()
64 .or_else(|_| EnvFilter::try_new(&filter))
65 .unwrap_or_else(|_| EnvFilter::new("off"));
66
67 match format.as_str() {
68 "json" => {
69 let _ = fmt().json().with_env_filter(env_filter).try_init();
70 }
71 "pretty" => {
72 let _ = fmt().pretty().with_env_filter(env_filter).try_init();
73 }
74 _ => {
75 let _ = fmt().compact().with_env_filter(env_filter).try_init();
76 }
77 }
78}
79
80#[cfg(not(feature = "tracing"))]
81pub fn init_tracing() {}
82
83#[cfg(feature = "tracing")]
96pub fn create_span(name: &str, fields: &[(&str, &str)]) -> Span {
97 let span = span!(Level::INFO, "op", name = name);
98 for (key, value) in fields {
99 span.record(*key, value);
100 }
101 span
102}
103
104#[cfg(not(feature = "tracing"))]
105pub fn create_span(_name: &str, _fields: &[(&str, &str)]) {}
106
107#[cfg(feature = "tracing")]
109pub fn create_debug_span(name: &str, fields: &[(&str, &str)]) -> Span {
110 let span = span!(Level::DEBUG, "debug_op", name = name);
111 for (key, value) in fields {
112 span.record(*key, value);
113 }
114 span
115}
116
117#[cfg(not(feature = "tracing"))]
118pub fn create_debug_span(_name: &str, _fields: &[(&str, &str)]) {}
119
120#[cfg(feature = "tracing")]
122pub fn create_trace_span(name: &str, fields: &[(&str, &str)]) -> Span {
123 let span = span!(Level::TRACE, "trace_op", name = name);
124 for (key, value) in fields {
125 span.record(*key, value);
126 }
127 span
128}
129
130#[cfg(not(feature = "tracing"))]
131pub fn create_trace_span(_name: &str, _fields: &[(&str, &str)]) {}
132
133#[cfg(feature = "tracing")]
135pub type SpanGuard = Span;
136
137#[cfg(not(feature = "tracing"))]
138pub type SpanGuard = ();
139
140#[macro_export]
149#[cfg(feature = "tracing")]
150macro_rules! span_scope {
151 ($name:expr) => {
152 let _guard = $crate::tracing::create_span($name, &[]);
153 };
154 ($name:expr, $($key:tt = $val:expr),*) => {
155 {
156 let fields = vec![$(( stringify!($key), &format!("{}", $val) as &str ),)*];
157 let _guard = $crate::tracing::create_span($name, &fields);
158 }
159 };
160}
161
162#[cfg(not(feature = "tracing"))]
163#[macro_export]
164macro_rules! span_scope {
165 ($name:expr $(, $key:tt = $val:expr)*) => {
166 ()
167 };
168}
169
170#[cfg(feature = "tracing")]
172pub fn record_event(level: EventLevel, message: &str, fields: &[(&str, &str)]) {
173 match level {
174 EventLevel::Error => tracing::error!(message = %message, ?fields),
175 EventLevel::Warn => tracing::warn!(message = %message, ?fields),
176 EventLevel::Info => tracing::info!(message = %message, ?fields),
177 EventLevel::Debug => tracing::debug!(message = %message, ?fields),
178 EventLevel::Trace => tracing::trace!(message = %message, ?fields),
179 }
180}
181
182#[cfg(not(feature = "tracing"))]
183pub fn record_event(_level: EventLevel, message: &str, _fields: &[(&str, &str)]) {
184 if matches!(_level, EventLevel::Error | EventLevel::Warn) {
185 eprintln!("[{}] {}", _level.as_str(), message);
186 }
187}
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq)]
191pub enum EventLevel {
192 Error,
193 Warn,
194 Info,
195 Debug,
196 Trace,
197}
198
199impl EventLevel {
200 pub fn as_str(&self) -> &'static str {
201 match self {
202 EventLevel::Error => "ERROR",
203 EventLevel::Warn => "WARN",
204 EventLevel::Info => "INFO",
205 EventLevel::Debug => "DEBUG",
206 EventLevel::Trace => "TRACE",
207 }
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use super::*;
214
215 #[test]
216 fn test_init_tracing_no_panic() {
217 init_tracing();
219 }
220
221 #[test]
222 fn test_span_creation() {
223 let _span = create_span("test_op", &[("key", "value")]);
224 }
226
227 #[test]
228 fn test_event_recording() {
229 record_event(EventLevel::Info, "test message", &[("field", "value")]);
230 }
232
233 #[test]
234 fn test_event_level_str() {
235 assert_eq!(EventLevel::Error.as_str(), "ERROR");
236 assert_eq!(EventLevel::Info.as_str(), "INFO");
237 }
238}