udf/
macros.rs

1//! macro definitions
2
3/// Print a formatted log message to `stderr` to display in server logs
4///
5/// Performs formatting to match other common SQL error logs, roughly:
6///
7/// ```text
8/// 2022-10-15 13:12:54+00:00 [Warning] Udf: this is the message
9/// ```
10///
11/// ```
12/// # #[cfg(not(miri))] // need to skip Miri because. it can't cross FFI
13/// # fn test() {
14///
15/// use udf::udf_log;
16///
17/// // Prints "2022-10-08 05:27:30+00:00 [Error] UDF: this is an error"
18/// // This matches the default entrypoint log format
19/// udf_log!(Error: "this is an error");
20///
21/// udf_log!(Warning: "this is a warning");
22///
23/// udf_log!(Note: "this is info: value {}", 10 + 10);
24///
25/// udf_log!(Debug: "this is a debug message");
26///
27/// udf_log!("i print without the '[Level] UDF:' formatting");
28///
29/// # }
30/// # #[cfg(not(miri))]
31/// # test();
32/// ```
33#[macro_export]
34macro_rules! udf_log {
35    (Critical: $($msg:tt)*) => {{
36        let formatted = format!("[Critical] UDF: {}", format!($($msg)*));
37        udf_log!(formatted);
38    }};
39    (Error: $($msg:tt)*) => {{
40        let formatted = format!("[Error] UDF: {}", format!($($msg)*));
41        udf_log!(formatted);
42    }};
43    (Warning: $($msg:tt)*) => {{
44        let formatted = format!("[Warning] UDF: {}", format!($($msg)*));
45        udf_log!(formatted);
46    }};
47    (Note: $($msg:tt)*) => {{
48        let formatted = format!("[Note] UDF: {}", format!($($msg)*));
49        udf_log!(formatted);
50    }};
51    (Debug: $($msg:tt)*) => {{
52        let formatted = format!("[Debug] UDF: {}", format!($($msg)*));
53        udf_log!(formatted);
54    }};
55    ($msg:tt) => {
56        eprintln!(
57            "{} {}",
58            $crate::chrono::Utc::now().format("%Y-%m-%d %H:%M:%S%:z"),
59            $msg
60        );
61    };
62}
63
64/// Log a call to a function, with optional printing of state
65///
66/// Log calls are only printed with feature "logging-debug". Call state is only
67/// printed with feature "logging-debug-calls".
68macro_rules! log_call {
69    // Log for entering a function
70    (enter: $name:literal, $type:ty, $($state:expr),*) => {
71        log_call!(@common: "ENTER", "receive", $name, $type, $($state),*)
72    };
73
74    // Logging for exiting a function
75    (exit: $name:literal, $type:ty, $($state:expr),*) => {
76        log_call!(@common: "EXIT", "return", $name, $type, $($state),*)
77    };
78
79    // Internal macro, common enter/exit printing
80    (@common:
81        $enter_or_exit:literal,
82        $receive_or_return:literal,
83        $fn_name:literal,
84        $type:ty,
85        $($state:expr),*
86    ) => {{
87        #[cfg(feature = "logging-debug")]
88        $crate::udf_log!(
89            Debug: "{} {} for '{}'",
90            $enter_or_exit, $fn_name, std::any::type_name::<$type>()
91        );
92
93        cfg_if::cfg_if! {
94            if #[cfg(feature = "logging-debug-calls")] {
95                $crate::udf_log!(Debug: "data {} state at {}", $receive_or_return, $fn_name);
96                // For each specified item, print the expression and its value
97                $(
98                    $crate::udf_log!(
99                        Debug: "[{}]: {} = {:#?}",
100                        $receive_or_return, std::stringify!($state), $state
101                    );
102                )*
103            }
104        }
105    }}
106}