1use std::sync::atomic::{AtomicU8, Ordering};
11
12pub const QUIET: u8 = 0;
13pub const NORMAL: u8 = 1;
14pub const VERBOSE: u8 = 2;
15
16static LEVEL: AtomicU8 = AtomicU8::new(NORMAL);
17
18pub fn init(verbose: bool, quiet: bool) {
21 let level = if verbose {
22 VERBOSE
23 } else if quiet {
24 QUIET
25 } else {
26 NORMAL
27 };
28 LEVEL.store(level, Ordering::Relaxed);
29 #[cfg(feature = "_semantic")]
30 init_log_backend(level);
31}
32
33pub fn level() -> u8 {
34 LEVEL.load(Ordering::Relaxed)
35}
36
37pub fn is_quiet() -> bool {
38 level() == QUIET
39}
40
41pub fn is_verbose() -> bool {
42 level() >= VERBOSE
43}
44
45#[macro_export]
47macro_rules! status {
48 ($($arg:tt)*) => {
49 if $crate::logging::level() >= $crate::logging::NORMAL {
50 eprintln!("gqls: {}", format_args!($($arg)*));
51 }
52 };
53}
54
55#[macro_export]
57macro_rules! detail {
58 ($($arg:tt)*) => {
59 if $crate::logging::is_verbose() {
60 eprintln!("gqls: {}", format_args!($($arg)*));
61 }
62 };
63}
64
65#[cfg(feature = "_semantic")]
70fn init_log_backend(level: u8) {
71 use log::LevelFilter;
72
73 static LOGGER: StderrLogger = StderrLogger;
74 let filter = match level {
75 QUIET => LevelFilter::Off,
76 VERBOSE => LevelFilter::Debug,
77 _ => LevelFilter::Warn,
78 };
79 let _ = log::set_logger(&LOGGER);
81 log::set_max_level(filter);
82}
83
84#[cfg(feature = "_semantic")]
85struct StderrLogger;
86
87#[cfg(feature = "_semantic")]
88impl log::Log for StderrLogger {
89 fn enabled(&self, meta: &log::Metadata) -> bool {
90 let t = meta.target();
94 t == "gqls" || t.starts_with("gqls::")
95 }
96
97 fn log(&self, record: &log::Record) {
98 if self.enabled(record.metadata()) {
99 eprintln!(
100 "gqls: [{}] {}",
101 record.level().as_str().to_ascii_lowercase(),
102 record.args()
103 );
104 }
105 }
106
107 fn flush(&self) {}
108}