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 {
30 Self { level }
31 }
32
33 pub fn level(&self) -> LevelFilter {
34 LevelFilter::from_level(self.level)
35 }
36
37 pub fn init(&self) {
38 let filter = EnvFilter::builder()
39 .with_default_directive(self.level().into()) .from_env_lossy() .add_directive("h2=warn".parse().unwrap())
42 .add_directive("quinn=info".parse().unwrap())
43 .add_directive("tracing::span=off".parse().unwrap())
44 .add_directive("tracing::span::active=off".parse().unwrap())
45 .add_directive("tokio=info".parse().unwrap())
46 .add_directive("runtime=info".parse().unwrap());
47
48 let fmt_layer = tracing_subscriber::fmt::layer()
49 .with_writer(std::io::stderr)
50 .with_filter(filter);
51
52 #[cfg(feature = "tokio-console")]
53 {
54 let console_layer = console_subscriber::spawn();
55 tracing_subscriber::registry()
56 .with(fmt_layer)
57 .with(console_layer)
58 .init();
59 }
60
61 #[cfg(not(feature = "tokio-console"))]
62 {
63 tracing_subscriber::registry().with(fmt_layer).init();
64 }
65
66 #[cfg(debug_assertions)]
68 std::thread::spawn(Self::deadlock_detector);
69 }
70
71 #[cfg(debug_assertions)]
72 fn deadlock_detector() {
73 loop {
74 std::thread::sleep(std::time::Duration::from_secs(1));
75
76 let deadlocks = parking_lot::deadlock::check_deadlock();
77 if deadlocks.is_empty() {
78 continue;
79 }
80
81 tracing::error!("DEADLOCK DETECTED");
82
83 for (i, threads) in deadlocks.iter().enumerate() {
84 tracing::error!("Deadlock #{}", i);
85 for t in threads {
86 tracing::error!("Thread Id {:#?}", t.thread_id());
87 tracing::error!("{:#?}", t.backtrace());
88 }
89 }
90
91 }
93 }
94}