mirror_common/
logger.rs

1#[cfg(all(not(debug_assertions)))]
2use std::fs::{create_dir, metadata};
3
4#[cfg(target_os = "android")]
5use std::ffi::{c_char, c_int};
6
7use fern::Dispatch;
8use log::LevelFilter;
9use thiserror::Error;
10
11#[cfg(not(debug_assertions))]
12use chrono::Local;
13
14#[cfg(debug_assertions)]
15use fern::colors::{Color, ColoredLevelConfig};
16
17#[cfg(all(not(debug_assertions)))]
18use fern::DateBased;
19
20#[derive(Debug, Error)]
21pub enum LoggerInitError {
22    #[error(transparent)]
23    LogError(#[from] log::SetLoggerError),
24    #[error(transparent)]
25    IoError(#[from] std::io::Error),
26}
27
28#[allow(unused_variables)]
29pub fn init_logger(level: LevelFilter, path: Option<&str>) -> Result<(), LoggerInitError> {
30    let mut logger = Dispatch::new()
31        .level(level)
32        .level_for("wgpu", LevelFilter::Warn)
33        .level_for("wgpu_core", LevelFilter::Warn)
34        .level_for("wgpu_hal", LevelFilter::Warn)
35        .level_for("wgpu_hal::auxil::dxgi::exception", LevelFilter::Error);
36
37    #[cfg(debug_assertions)]
38    {
39        let colors = ColoredLevelConfig::new()
40            .info(Color::Blue)
41            .warn(Color::Yellow)
42            .error(Color::Red);
43
44        logger = logger
45            .format(move |out, message, record| {
46                out.finish(format_args!(
47                    "[{}] - ({}) - {}",
48                    colors.color(record.level()),
49                    record.file_static().unwrap_or("*"),
50                    message
51                ))
52            })
53            .chain(std::io::stdout());
54    }
55
56    #[cfg(not(debug_assertions))]
57    {
58        logger = logger.format(move |out, message, record| {
59            out.finish(format_args!(
60                "{} - [{}] - ({}) - {}",
61                Local::now().format("%m-%d %H:%M:%S"),
62                record.level(),
63                record.file_static().unwrap_or("*"),
64                message
65            ))
66        });
67
68        if let Some(path) = path {
69            if metadata(path).is_err() {
70                create_dir(path)?;
71            }
72
73            logger = logger.chain(DateBased::new(path, "%Y-%m-%d-mirror.log"))
74        } else {
75            logger = logger.chain(std::io::stdout());
76        }
77    }
78
79    logger.apply()?;
80
81    #[cfg(not(debug_assertions))]
82    std::panic::set_hook(Box::new(|info| {
83        log::error!(
84            "pnaic: location={:?}, message={:?}",
85            info.location(),
86            info.payload().downcast_ref::<String>(),
87        );
88    }));
89
90    Ok(())
91}
92
93#[repr(C)]
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
95pub enum AndroidLogLevel {
96    Verbose = 2,
97    Debug,
98    Info,
99    Warn,
100    Error,
101}
102
103impl AndroidLogLevel {
104    pub fn from_level(level: log::Level) -> Self {
105        match level {
106            log::Level::Trace => Self::Verbose,
107            log::Level::Debug => Self::Debug,
108            log::Level::Info => Self::Info,
109            log::Level::Warn => Self::Warn,
110            log::Level::Error => Self::Error,
111        }
112    }
113}
114
115#[cfg(target_os = "android")]
116extern "C" {
117    // __android_log_write
118    //
119    //
120    // int __android_log_write(
121    //   int prio,
122    //   const char *tag,
123    //   const char *text
124    // )
125    //
126    // Writes the constant string text to the log, with priority prio and tag tag.
127    #[link_name = "__android_log_write"]
128    fn android_log_write(prio: c_int, tag: *const c_char, text: *const c_char) -> c_int;
129}
130
131pub struct AndroidLogger;
132
133impl log::Log for AndroidLogger {
134    fn flush(&self) {}
135    fn enabled(&self, _: &log::Metadata) -> bool {
136        true
137    }
138
139    #[allow(unused_variables)]
140    fn log(&self, record: &log::Record) {
141        #[cfg(target_os = "android")]
142        unsafe {
143            android_log_write(
144                AndroidLogLevel::from_level(record.level()) as c_int,
145                "com.github.mycrl.mirror\0".as_ptr() as *const _,
146                format!("{}\0", record.args()).as_ptr() as *const _,
147            );
148        }
149    }
150}
151
152pub fn init_with_android(level: LevelFilter) {
153    log::set_boxed_logger(Box::new(AndroidLogger)).unwrap();
154    log::set_max_level(level);
155
156    #[cfg(not(debug_assertions))]
157    std::panic::set_hook(Box::new(|info| {
158        log::error!(
159            "pnaic: location={:?}, message={:?}",
160            info.location(),
161            info.payload().downcast_ref::<String>(),
162        );
163    }));
164}