Skip to main content

fswtch/
logging.rs

1use std::{ffi::CString, fmt};
2
3use crate::sys;
4
5macro_rules! call_ffi {
6    ($call:expr) => {{
7        // SAFETY: The caller documents the FreeSWITCH ABI preconditions at each call site.
8        unsafe { $call }
9    }};
10}
11
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum LogLevel {
14    Disable,
15    Console,
16    Alert,
17    Critical,
18    Error,
19    Warning,
20    Notice,
21    Info,
22    Debug,
23    Debug1,
24    Debug2,
25    Debug3,
26    Debug4,
27    Debug5,
28    Debug6,
29    Debug7,
30    Debug8,
31    Debug9,
32    Debug10,
33    Invalid,
34    Uninit,
35}
36
37impl LogLevel {
38    pub const fn as_raw(self) -> sys::switch_log_level_t {
39        match self {
40            Self::Disable => sys::switch_log_level_t_SWITCH_LOG_DISABLE,
41            Self::Console => sys::switch_log_level_t_SWITCH_LOG_CONSOLE,
42            Self::Alert => sys::switch_log_level_t_SWITCH_LOG_ALERT,
43            Self::Critical => sys::switch_log_level_t_SWITCH_LOG_CRIT,
44            Self::Error => sys::switch_log_level_t_SWITCH_LOG_ERROR,
45            Self::Warning => sys::switch_log_level_t_SWITCH_LOG_WARNING,
46            Self::Notice => sys::switch_log_level_t_SWITCH_LOG_NOTICE,
47            Self::Info => sys::switch_log_level_t_SWITCH_LOG_INFO,
48            Self::Debug => sys::switch_log_level_t_SWITCH_LOG_DEBUG,
49            Self::Debug1 => sys::switch_log_level_t_SWITCH_LOG_DEBUG1,
50            Self::Debug2 => sys::switch_log_level_t_SWITCH_LOG_DEBUG2,
51            Self::Debug3 => sys::switch_log_level_t_SWITCH_LOG_DEBUG3,
52            Self::Debug4 => sys::switch_log_level_t_SWITCH_LOG_DEBUG4,
53            Self::Debug5 => sys::switch_log_level_t_SWITCH_LOG_DEBUG5,
54            Self::Debug6 => sys::switch_log_level_t_SWITCH_LOG_DEBUG6,
55            Self::Debug7 => sys::switch_log_level_t_SWITCH_LOG_DEBUG7,
56            Self::Debug8 => sys::switch_log_level_t_SWITCH_LOG_DEBUG8,
57            Self::Debug9 => sys::switch_log_level_t_SWITCH_LOG_DEBUG9,
58            Self::Debug10 => sys::switch_log_level_t_SWITCH_LOG_DEBUG10,
59            Self::Invalid => sys::switch_log_level_t_SWITCH_LOG_INVALID,
60            Self::Uninit => sys::switch_log_level_t_SWITCH_LOG_UNINIT,
61        }
62    }
63}
64
65#[inline]
66pub fn log(module: &str, level: LogLevel, message: impl fmt::Display) {
67    log_at(level.as_raw(), module, message);
68}
69
70pub fn log_console(module: &str, message: impl fmt::Display) {
71    log(module, LogLevel::Console, message);
72}
73
74pub fn log_alert(module: &str, message: impl fmt::Display) {
75    log(module, LogLevel::Alert, message);
76}
77
78pub fn log_critical(module: &str, message: impl fmt::Display) {
79    log(module, LogLevel::Critical, message);
80}
81
82pub fn log_error(module: &str, message: impl fmt::Display) {
83    log(module, LogLevel::Error, message);
84}
85
86pub fn log_warning(module: &str, message: impl fmt::Display) {
87    log(module, LogLevel::Warning, message);
88}
89
90pub fn log_notice(module: &str, message: impl fmt::Display) {
91    log(module, LogLevel::Notice, message);
92}
93
94pub fn log_info(module: &str, message: impl fmt::Display) {
95    log(module, LogLevel::Info, message);
96}
97
98pub fn log_debug(module: &str, message: impl fmt::Display) {
99    log(module, LogLevel::Debug, message);
100}
101
102pub fn log_debug1(module: &str, message: impl fmt::Display) {
103    log(module, LogLevel::Debug1, message);
104}
105
106pub fn log_debug2(module: &str, message: impl fmt::Display) {
107    log(module, LogLevel::Debug2, message);
108}
109
110pub fn log_debug3(module: &str, message: impl fmt::Display) {
111    log(module, LogLevel::Debug3, message);
112}
113
114pub fn log_debug4(module: &str, message: impl fmt::Display) {
115    log(module, LogLevel::Debug4, message);
116}
117
118pub fn log_debug5(module: &str, message: impl fmt::Display) {
119    log(module, LogLevel::Debug5, message);
120}
121
122pub fn log_debug6(module: &str, message: impl fmt::Display) {
123    log(module, LogLevel::Debug6, message);
124}
125
126pub fn log_debug7(module: &str, message: impl fmt::Display) {
127    log(module, LogLevel::Debug7, message);
128}
129
130pub fn log_debug8(module: &str, message: impl fmt::Display) {
131    log(module, LogLevel::Debug8, message);
132}
133
134pub fn log_debug9(module: &str, message: impl fmt::Display) {
135    log(module, LogLevel::Debug9, message);
136}
137
138pub fn log_debug10(module: &str, message: impl fmt::Display) {
139    log(module, LogLevel::Debug10, message);
140}
141
142pub fn log_example(module: &str, message: impl fmt::Display) {
143    log_info(module, message);
144}
145
146pub fn log_example_error(module: &str, message: impl fmt::Display) {
147    log_error(module, message);
148}
149
150fn log_at(level: sys::switch_log_level_t, module: &str, message: impl fmt::Display) {
151    let text = format!("[fswtch:{module}] {message}");
152    let text = text.replace('\0', "\\0");
153    let Ok(text) = CString::new(text) else {
154        return;
155    };
156
157    // SAFETY: All C strings are valid for the duration of the varargs logging call.
158    unsafe { log_printf(level, text.as_ptr()) };
159}
160
161/// # Safety
162///
163/// `text` must point to a live null-terminated C string for this varargs call.
164// SAFETY: The caller must pass a live null-terminated message pointer.
165unsafe fn log_printf(level: sys::switch_log_level_t, text: *const std::ffi::c_char) {
166    let log = sys::switch_log_printf;
167    let channel = sys::switch_text_channel_t_SWITCH_CHANNEL_ID_LOG;
168    call_ffi!(log(
169        channel,
170        c"fswtch-rs".as_ptr(),
171        c"log".as_ptr(),
172        line!() as _,
173        std::ptr::null(),
174        level,
175        c"%s\n".as_ptr(),
176        text,
177    ));
178}