jay-compositor 1.15.0

The Jay compositor
use crate::utils::clonecell::CloneCell;
use log::Level;
use log::LevelFilter;
use log::Log;
use log::Metadata;
use log::Record;
use std::fmt::Write as FmtWrite;
use std::io::Write;
use std::rc::Rc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
use std::time::SystemTime;
use uapi::Fd;
use uapi::OwnedFd;

static LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize);

thread_local! {
    static FILE: CloneCell<Option<Rc<OwnedFd>>> = const { CloneCell::new(None) };
}

pub fn install() {
    let _ = log::set_logger(&Logger);
    log::set_max_level(LevelFilter::Info);
}

pub fn set_level(level: Level) {
    LEVEL.store(level as usize, Ordering::Relaxed);
    log::set_max_level(level.to_level_filter());
}

pub fn set_file(file: Rc<OwnedFd>) {
    FILE.with(|f| f.set(Some(file)));
}

pub fn unset_file() {
    FILE.with(|f| f.set(None));
}

struct Logger;

impl Log for Logger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() as usize <= LEVEL.load(Ordering::Relaxed)
    }

    fn log(&self, record: &Record<'_>) {
        if record.level() as usize > LEVEL.load(Ordering::Relaxed) {
            return;
        }
        let mut buf = String::new();
        let now = SystemTime::now();
        let _ = if let Some(mp) = record.module_path() {
            writeln!(
                buf,
                "[{} {:5} {}] {}",
                humantime::format_rfc3339_millis(now),
                record.level(),
                mp,
                record.args(),
            )
        } else {
            writeln!(
                buf,
                "[{} {:5}] {}",
                humantime::format_rfc3339_millis(now),
                record.level(),
                record.args(),
            )
        };
        let mut fd = match FILE.with(|f| f.get()) {
            Some(f) => f.borrow(),
            _ => Fd::new(2),
        };
        let _ = fd.write_all(buf.as_bytes());
    }

    fn flush(&self) {
        // nothing
    }
}