1use std::sync::OnceLock;
4
5use clap::ValueEnum;
6use tracing::{Subscriber, level_filters::LevelFilter, log::error};
7use tracing_subscriber::{
8 Layer, Registry,
9 fmt::{self, format::FmtSpan, time},
10 prelude::*,
11 registry::LookupSpan,
12 reload::{self, Handle},
13};
14
15use crate::settings::Settings;
16pub(crate) const LOG_LEVEL_DEFAULT: &str = "info";
18
19#[derive(ValueEnum, Clone, Copy, Debug)]
21pub(crate) enum LogLevel {
22 Debug,
24 Info,
26 Warn,
28 Error,
30}
31
32impl From<LogLevel> for tracing::Level {
33 fn from(val: LogLevel) -> Self {
34 match val {
35 LogLevel::Debug => Self::DEBUG,
36 LogLevel::Info => Self::INFO,
37 LogLevel::Warn => Self::WARN,
38 LogLevel::Error => Self::ERROR,
39 }
40 }
41}
42
43impl From<LogLevel> for tracing::log::LevelFilter {
44 fn from(val: LogLevel) -> Self {
45 match val {
46 LogLevel::Debug => Self::Debug,
47 LogLevel::Info => Self::Info,
48 LogLevel::Warn => Self::Warn,
49 LogLevel::Error => Self::Error,
50 }
51 }
52}
53
54static LOGGER_HANDLE: OnceLock<LoggerHandle> = OnceLock::new();
56
57static GLOBAL_SPAN: OnceLock<tracing::span::Span> = OnceLock::new();
59
60static SPAN_GUARD: OnceLock<tracing::span::Entered> = OnceLock::new();
62
63pub(crate) type LoggerHandle = Handle<LevelFilter, Registry>;
65
66fn set_default_span() {
68 let server_id = Settings::service_id();
69 let global_span = tracing::info_span!("Global", ServerID = server_id);
72 if GLOBAL_SPAN.set(global_span).is_err() {
73 error!("Failed to set default span. Is it already set?");
74 }
75
76 if let Some(global_span) = GLOBAL_SPAN.get() {
78 let span_guard = global_span.enter();
79 if SPAN_GUARD.set(span_guard).is_err() {
80 error!("Failed to set default span. Is it already set?");
81 }
82 }
83}
84
85pub(crate) fn build_fmt_layer<S>() -> Box<dyn Layer<S> + Send + Sync + 'static>
87where
88 S: Subscriber,
89 for<'a> S: LookupSpan<'a>,
90{
91 fmt::layer()
93 .json()
94 .with_timer(time::UtcTime::rfc_3339())
95 .with_span_events(FmtSpan::CLOSE)
96 .with_current_span(true)
97 .with_span_list(true)
98 .with_target(true)
99 .with_file(true)
100 .with_line_number(true)
101 .with_level(true)
102 .with_thread_names(true)
103 .with_thread_ids(true)
104 .flatten_event(true)
105 .boxed()
106}
107
108pub(crate) fn build_reloadable_filter(log_level: LogLevel) -> reload::Layer<LevelFilter, Registry> {
113 let filter = LevelFilter::from_level(log_level.into());
114 let (filter, logger_handle) = reload::Layer::new(filter);
115
116 if LOGGER_HANDLE.set(logger_handle).is_err() {
117 error!("Failed to initialize logger handle. Called multiple times?");
118 }
119 filter
120}
121
122pub(crate) fn init(log_level: LogLevel) {
124 let layer = build_fmt_layer();
126
127 let filter = build_reloadable_filter(log_level);
129
130 tracing_subscriber::registry()
131 .with(filter)
132 .with(layer)
133 .with(
134 tracing_subscriber::EnvFilter::builder()
135 .with_default_directive(LevelFilter::INFO.into())
136 .from_env_lossy(),
137 )
138 .init();
139
140 post_init(log_level);
141}
142
143pub(crate) fn post_init(log_level: LogLevel) {
145 tracing::log::set_max_level(log_level.into());
147 set_default_span();
148}
149
150pub(crate) fn modify_logger_level(level: LogLevel) {
153 if let Some(logger_handle) = LOGGER_HANDLE.get() {
154 if let Err(error) = logger_handle.modify(|f| *f = LevelFilter::from_level(level.into())) {
155 error!("Failed to modify log level to {level:?} : {error}");
156 }
157 } else {
158 error!("Failed to modify log level to {level:?} : Logger handle not available.",);
160 }
161}