freeswitch_rs/
fslog.rs

1use freeswitch_sys::{switch_log_level_t, switch_log_printf, switch_text_channel_t};
2use log::Log;
3use std::{ffi::CString, ptr::null};
4
5use crate::{
6    core::{Session, SessionExt},
7    utils::FSNewType,
8};
9
10#[repr(transparent)]
11pub struct FSTextChannel(switch_text_channel_t);
12
13macro_rules! logging_macro {
14    ($name:ident, $t:expr, $fn:expr) => {
15        #[macro_export]
16        macro_rules! $name {
17            ($e:expr) => {
18                $crate::fslog::FSLoggerWithData(($fn)($e), $t)
19            };
20            () => {
21                $crate::fslog::FSLoggerWithData(($fn)($e), $t)
22            };
23        }
24        pub use $name;
25    };
26}
27
28#[doc(hidden)]
29pub fn convert_session<T: SessionExt>(s: &T) -> *const ::std::os::raw::c_char {
30    s.as_ptr().cast()
31}
32
33#[doc(hidden)]
34pub fn convert_session_clean<T: SessionExt>(s: &T) -> *const ::std::os::raw::c_char {
35    s.get_uuid().as_ptr().cast()
36}
37
38logging_macro!(channel_log, SWITCH_CHANNEL_ID_LOG, || null().cast());
39logging_macro!(channel_log_clean, SWITCH_CHANNEL_ID_LOG_CLEAN, || null()
40    .cast());
41logging_macro!(
42    session_log,
43    SWITCH_CHANNEL_ID_SESSION,
44    freeswitch_rs::fslog::convert_session
45);
46logging_macro!(
47    session_log_clean,
48    SWITCH_CHANNEL_ID_SESSION,
49    freeswitch_rs::fslog::convert_session_clean
50);
51
52pub const SWITCH_CHANNEL_ID_LOG: FSTextChannel =
53    FSTextChannel(switch_text_channel_t::SWITCH_CHANNEL_ID_LOG);
54pub const SWITCH_CHANNEL_ID_LOG_CLEAN: FSTextChannel =
55    FSTextChannel(switch_text_channel_t::SWITCH_CHANNEL_ID_LOG_CLEAN);
56pub const SWITCH_CHANNEL_ID_EVENT: FSTextChannel =
57    FSTextChannel(switch_text_channel_t::SWITCH_CHANNEL_ID_EVENT);
58pub const SWITCH_CHANNEL_ID_SESSION: FSTextChannel =
59    FSTextChannel(switch_text_channel_t::SWITCH_CHANNEL_ID_SESSION);
60
61// ==========
62pub struct FSLoggerWithData(pub *const ::std::os::raw::c_char, pub FSTextChannel);
63//
64unsafe impl Send for FSLoggerWithData {}
65unsafe impl Sync for FSLoggerWithData {}
66
67impl Log for FSLoggerWithData {
68    fn enabled(&self, metadata: &log::Metadata) -> bool {
69        FSLogger.enabled(metadata)
70    }
71    fn log(&self, record: &log::Record) {
72        FSLogger.log_with_userdata(record, SWITCH_CHANNEL_ID_SESSION, self.0.cast());
73    }
74    fn flush(&self) {
75        FSLogger.flush();
76    }
77}
78
79// We provide an adapter over switch logging so mod authors can use the standard
80// log crate facarde. Still working out how to pass user data back ....
81pub struct FSLogger;
82
83impl FSLogger {
84    fn log_with_userdata(
85        &self,
86        record: &log::Record,
87        text_channel: FSTextChannel,
88        userdata: *const ::std::os::raw::c_char,
89    ) {
90        if self.enabled(record.metadata()) {
91            let file = record
92                .file()
93                .and_then(|s| CString::new(s).ok())
94                .map(|s| s.into_raw());
95            let line = record.line().unwrap_or(0);
96            let func = std::ptr::null();
97            let level = match record.metadata().level() {
98                log::Level::Warn => switch_log_level_t::SWITCH_LOG_WARNING,
99                log::Level::Info => switch_log_level_t::SWITCH_LOG_INFO,
100                log::Level::Error => switch_log_level_t::SWITCH_LOG_ERROR,
101                log::Level::Debug => switch_log_level_t::SWITCH_LOG_DEBUG,
102                log::Level::Trace => switch_log_level_t::SWITCH_LOG_DEBUG10,
103            };
104            let fmt = format!("{}\n", record.args());
105            let fmt_c = CString::new(fmt).unwrap();
106
107            unsafe {
108                switch_log_printf(
109                    text_channel.0,
110                    file.unwrap_or(std::ptr::null_mut()),
111                    func,
112                    line.try_into().unwrap_or(0),
113                    userdata,
114                    level,
115                    fmt_c.into_raw(),
116                )
117            }
118        }
119    }
120}
121
122impl Log for FSLogger {
123    fn enabled(&self, _metadata: &log::Metadata) -> bool {
124        true
125    }
126
127    fn log(&self, record: &log::Record) {
128        self.log_with_userdata(record, SWITCH_CHANNEL_ID_LOG, null());
129    }
130
131    fn flush(&self) {}
132}