openconnect_core/
log.rs

1use openconnect_sys::{PRG_DEBUG, PRG_ERR, PRG_INFO, PRG_TRACE};
2use tracing::{
3    event,
4    subscriber::{set_global_default, SetGlobalDefaultError},
5    Level,
6};
7use tracing_appender::rolling::{RollingFileAppender, Rotation};
8
9pub struct Logger;
10
11impl Logger {
12    pub fn get_log_path() -> &'static str {
13        #[cfg(target_os = "linux")]
14        const LOG_PATH: &str = "/var/log/openconnect-rs";
15
16        #[cfg(target_os = "macos")]
17        const LOG_PATH: &str = "/Library/Logs/openconnect-rs";
18
19        #[cfg(target_os = "windows")]
20        const LOG_PATH: &str = "C:\\ProgramData\\openconnect-rs";
21
22        LOG_PATH
23    }
24
25    pub fn init() -> Result<(), SetGlobalDefaultError> {
26        let file_appender = RollingFileAppender::builder()
27            .max_log_files(5)
28            .rotation(Rotation::DAILY)
29            .filename_prefix("openconnect-rs.log")
30            .build(Self::get_log_path())
31            .expect("failed to create file appender");
32
33        // for file based logging, waiting https://github.com/tokio-rs/tracing/pull/2497 to be merged
34        let subscriber = tracing_subscriber::fmt()
35            .compact()
36            .with_level(true)
37            .with_target(true)
38            .with_max_level(Level::TRACE)
39            .with_writer(file_appender)
40            .finish();
41
42        set_global_default(subscriber)
43    }
44
45    pub(crate) unsafe extern "C" fn raw_handle_process_log(
46        _privdata: *mut ::std::os::raw::c_void,
47        level: ::std::os::raw::c_int,
48        buf: *const ::std::os::raw::c_char,
49    ) {
50        let buf = std::ffi::CStr::from_ptr(buf).to_str().ok();
51        let level = level as u32;
52        let level = match level {
53            PRG_ERR => Level::ERROR,
54            PRG_INFO => Level::INFO,
55            PRG_DEBUG => Level::DEBUG,
56            PRG_TRACE => Level::TRACE,
57            _ => unreachable!("unknown log level: {}", level),
58        };
59        if buf.is_some() {
60            Logger::log(level, buf.unwrap_or(""));
61        }
62    }
63
64    pub fn log(level: Level, message: &str) {
65        match level {
66            Level::ERROR => event!(Level::ERROR, "{}", message),
67            Level::WARN => event!(Level::WARN, "{}", message),
68            Level::INFO => event!(Level::INFO, "{}", message),
69            Level::DEBUG => event!(Level::DEBUG, "{}", message),
70            Level::TRACE => event!(Level::TRACE, "{}", message),
71        }
72    }
73}