1use std::str::FromStr;
2use tracing::{instrument, Level};
3use tracing_subscriber::{
4 fmt::{self, format::FmtSpan},
5 layer::SubscriberExt,
6 util::SubscriberInitExt,
7 Layer,
8 Registry,
9};
10
11pub mod metrics;
13pub use metrics::PerformanceMetrics;
14
15#[derive(Debug, Clone, Copy)]
16pub enum LogLevel {
17 Trace,
18 Debug,
19 Info,
20 Warn,
21 Error,
22}
23impl FromStr for LogLevel {
24 type Err = String;
25
26 fn from_str(s: &str) -> Result<Self, Self::Err> {
27 match s.to_lowercase().as_str() {
28 "trace" => Ok(LogLevel::Trace),
29 "debug" => Ok(LogLevel::Debug),
30 "info" => Ok(LogLevel::Info),
31 "warn" => Ok(LogLevel::Warn),
32 "error" => Ok(LogLevel::Error),
33 _ => Err(format!("Invalid log level: {}", s)),
34 }
35 }
36}
37
38impl From<LogLevel> for Level {
39 fn from(level: LogLevel) -> Self {
40 match level {
41 LogLevel::Trace => Level::TRACE,
42 LogLevel::Debug => Level::DEBUG,
43 LogLevel::Info => Level::INFO,
44 LogLevel::Warn => Level::WARN,
45 LogLevel::Error => Level::ERROR,
46 }
47 }
48}
49
50#[derive(Debug)]
51pub struct LogConfig {
52 pub level: LogLevel,
53 pub enable_tracy: bool,
54 pub log_spans: bool,
56}
57
58impl Default for LogConfig {
59 fn default() -> Self {
60 Self {
61 level: LogLevel::Info,
62 enable_tracy: false,
63 log_spans: true,
64 }
65 }
66}
67
68#[instrument]
69pub fn init(config: LogConfig) {
70 let level = Level::from(config.level);
71 let filter = tracing_subscriber::filter::LevelFilter::from_level(level);
72
73 let fmt_layer = fmt::layer()
74 .with_line_number(true)
75 .with_thread_ids(true)
76 .with_file(true)
77 .with_timer(fmt::time::UtcTime::rfc_3339())
78 .with_span_events(FmtSpan::EXIT)
79 .with_filter(filter.clone());
80
81 let registry = Registry::default().with(fmt_layer);
82
83 if config.enable_tracy {
84 let tracy_layer =
86 tracing_tracy::TracyLayer::default().with_filter(filter);
87
88 registry
89 .with(tracy_layer)
90 .try_init()
91 .expect("Failed to initialize logging with tracy");
92
93 tracy_client::frame_mark();
96 } else {
97 registry
98 .try_init()
99 .expect("Failed to initialize logging");
100 }
101}
102
103#[instrument]
104pub fn get_log_level_from_env() -> LogLevel {
105 std::env::var("RUST_LOG")
106 .ok()
107 .and_then(|s| s.parse().ok())
108 .unwrap_or(LogLevel::Info)
109}