1use serde::{Deserialize, Serialize};
2use serde_with::DisplayFromStr;
3use tracing::Level;
4use tracing::level_filters::LevelFilter;
5use tracing_subscriber::EnvFilter;
6use tracing_subscriber::Layer;
7use tracing_subscriber::layer::SubscriberExt;
8use tracing_subscriber::util::SubscriberInitExt;
9
10#[serde_with::serde_as]
12#[derive(Clone, clap::Parser, Serialize, Deserialize, Debug)]
13#[serde(deny_unknown_fields, default)]
14#[non_exhaustive]
15pub struct Log {
16 #[serde_as(as = "DisplayFromStr")]
18 #[arg(id = "log-level", long = "log-level", default_value = "info", env = "MOQ_LOG_LEVEL")]
19 pub level: Level,
20}
21
22impl Default for Log {
23 fn default() -> Self {
24 Self { level: Level::INFO }
25 }
26}
27
28impl Log {
29 pub fn new(level: Level) -> Self {
31 Self { level }
32 }
33
34 pub fn level(&self) -> LevelFilter {
36 LevelFilter::from_level(self.level)
37 }
38
39 pub fn init(&self) -> crate::Result<()> {
45 let filter = EnvFilter::builder()
46 .with_default_directive(self.level().into()) .from_env_lossy() .add_directive("h2=warn".parse()?)
49 .add_directive("quinn=info".parse()?)
50 .add_directive("noq=info".parse()?)
51 .add_directive("tungstenite=info".parse()?)
52 .add_directive("rustls=info".parse()?)
53 .add_directive("tracing::span=off".parse()?)
54 .add_directive("tracing::span::active=off".parse()?)
55 .add_directive("tokio=info".parse()?)
56 .add_directive("runtime=info".parse()?);
57
58 let registry = tracing_subscriber::registry();
59
60 #[cfg(all(target_os = "android", feature = "android-logcat"))]
63 let registry = {
64 let logcat_layer = tracing_android::layer("MoQNative")
65 .map_err(|e| crate::Error::Logcat(std::sync::Arc::new(e)))?
66 .with_filter(filter);
67 registry.with(logcat_layer)
68 };
69
70 #[cfg(not(all(target_os = "android", feature = "android-logcat")))]
71 let registry = {
72 let fmt_layer = tracing_subscriber::fmt::layer()
73 .with_writer(std::io::stderr)
74 .with_filter(filter);
75 registry.with(fmt_layer)
76 };
77
78 registry
79 .try_init()
80 .map_err(|e| crate::Error::SetSubscriber(std::sync::Arc::new(e)))?;
81
82 #[cfg(debug_assertions)]
84 std::thread::spawn(Self::deadlock_detector);
85
86 Ok(())
87 }
88
89 #[cfg(debug_assertions)]
90 fn deadlock_detector() {
91 loop {
92 std::thread::sleep(std::time::Duration::from_secs(1));
93
94 let deadlocks = parking_lot::deadlock::check_deadlock();
95 if deadlocks.is_empty() {
96 continue;
97 }
98
99 tracing::error!("DEADLOCK DETECTED");
100
101 for (i, threads) in deadlocks.iter().enumerate() {
102 tracing::error!("Deadlock #{}", i);
103 for t in threads {
104 tracing::error!("Thread Id {:#?}", t.thread_id());
105 tracing::error!("{:#?}", t.backtrace());
106 }
107 }
108
109 }
111 }
112}