Skip to main content

state_engine/common/
log_format.rs

1use serde_json::Value;
2
3/// # Examples
4/// ```
5/// use state_engine::common::log_format::LogFormat;
6///
7/// let fn_message = LogFormat::call("State", "get", &["'key'".to_string()]);
8/// assert_eq!(fn_message, "State::get('key')");
9/// ```
10pub struct LogFormat;
11
12impl LogFormat {
13
14    pub fn call(class: &str, fn_name: &str, args: &[String]) -> String {
15        let args_str = args.join(", ");
16        format!("{}::{}({})", class, fn_name, args_str)
17    }
18
19    /// Format JSON value for log output
20    ///
21    /// # Examples
22    /// ```
23    /// use state_engine::common::log_format::LogFormat;
24    /// use serde_json::json;
25    ///
26    /// assert_eq!(LogFormat::format_arg(&json!("text")), "'text'");
27    /// assert_eq!(LogFormat::format_arg(&json!(42)), "42");
28    /// assert_eq!(LogFormat::format_arg(&json!(true)), "true");
29    /// assert_eq!(LogFormat::format_arg(&json!(null)), "null");
30    /// assert_eq!(LogFormat::format_arg(&json!([])), "[]");
31    /// assert_eq!(LogFormat::format_arg(&json!({})), "{}");
32    /// assert_eq!(LogFormat::format_arg(&json!([1, 2, 3])), "[3 items]");
33    /// assert_eq!(LogFormat::format_arg(&json!({"a": 1})), "{1 fields}");
34    /// ```
35    pub fn format_arg(value: &Value) -> String {
36        match value {
37            Value::String(s) if s.len() > 50 => {
38                format!("'{}'...", &s[..47])
39            }
40            Value::String(s) => {
41                format!("'{}'", s)
42            }
43            Value::Array(arr) => {
44                if arr.is_empty() {
45                    "[]".to_string()
46                } else {
47                    format!("[{} items]", arr.len())
48                }
49            }
50            Value::Object(obj) => {
51                if obj.is_empty() {
52                    "{}".to_string()
53                } else {
54                    format!("{{{} fields}}", obj.len())
55                }
56            }
57            Value::Null => "null".to_string(),
58            Value::Bool(b) => b.to_string(),
59            Value::Number(n) => n.to_string(),
60        }
61    }
62
63    /// Format string argument for log output
64    ///
65    /// # Examples
66    /// ```
67    /// use state_engine::common::log_format::LogFormat;
68    ///
69    /// assert_eq!(LogFormat::format_str_arg("key"), "'key'");
70    /// ```
71    pub fn format_str_arg(s: &str) -> String {
72        if s.len() > 50 {
73            format!("'{}'...", &s[..47])
74        } else {
75            format!("'{}'", s)
76        }
77    }
78}
79
80/// Log macro: fn call
81///
82/// # Examples
83/// ```ignore
84/// use crate::fn_log;
85///
86/// fn_log!("State", "get", "cache.user");
87/// // Logs: State::get('cache.user')
88/// ```
89#[macro_export]
90macro_rules! fn_log {
91    ($class:expr, $fun:expr $(, $arg:expr)*) => {{
92        #[cfg(feature = "logging")]
93        {
94            let args: Vec<String> = vec![
95                $(
96                    $crate::common::log_format::LogFormat::format_str_arg($arg),
97                )*
98            ];
99            log::debug!("{}", $crate::common::log_format::LogFormat::call($class, $fun, &args));
100        }
101    }};
102}
103
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    use serde_json::json;
109
110    #[test]
111    fn test_fn_multiple_args() {
112        let result = LogFormat::call("State", "get", &[
113            "'cache.user'".to_string(),
114            "null".to_string(),
115        ]);
116        assert_eq!(result, "State::get('cache.user', null)");
117    }
118
119    #[test]
120    fn test_format_arg_long_string() {
121        let long_str = "a".repeat(60);
122        let result = LogFormat::format_arg(&json!(long_str));
123        assert!(result.starts_with("'aaa"));
124        assert!(result.ends_with("'..."));
125        assert_eq!(result.len(), 52); // ' + 47 chars + '...
126    }
127
128    #[test]
129    fn test_format_str_arg_long_string() {
130        let long_str = "a".repeat(60);
131        let result = LogFormat::format_str_arg(&long_str);
132        assert!(result.starts_with("'aaa"));
133        assert!(result.ends_with("'..."));
134    }
135}