use serde_json::Value;
pub struct LogFormat;
impl LogFormat {
pub fn call(class: &str, fn_name: &str, args: &[String]) -> String {
let args_str = args.join(", ");
format!("{}::{}({})", class, fn_name, args_str)
}
pub fn format_arg(value: &Value) -> String {
match value {
Value::String(s) if s.len() > 50 => format!("'{}'...", &s[..47]),
Value::String(s) => format!("'{}'", s),
Value::Array(arr) if arr.is_empty() => "[]".to_string(),
Value::Array(arr) => format!("[{} items]", arr.len()),
Value::Object(obj) if obj.is_empty() => "{}".to_string(),
Value::Object(obj) => format!("{{{} fields}}", obj.len()),
Value::Null => "null".to_string(),
Value::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(),
}
}
pub fn format_str_arg(s: &str) -> String {
if s.len() > 50 {
format!("'{}'...", &s[..47])
} else {
format!("'{}'", s)
}
}
}
#[macro_export]
macro_rules! fn_log {
($class:expr, $fun:expr $(, $arg:expr)*) => {{
#[cfg(feature = "logging")]
{
let args: Vec<String> = vec![
$(
$crate::log_format::LogFormat::format_str_arg($arg),
)*
];
log::debug!("{}", $crate::log_format::LogFormat::call($class, $fun, &args));
}
}};
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_fn_multiple_args() {
let result = LogFormat::call("State", "get", &[
"'cache.user'".to_string(),
"null".to_string(),
]);
assert_eq!(result, "State::get('cache.user', null)");
}
#[test]
fn test_format_arg_long_string() {
let long_str = "a".repeat(60);
let result = LogFormat::format_arg(&json!(long_str));
assert!(result.starts_with("'aaa"));
assert!(result.ends_with("'..."));
assert_eq!(result.len(), 52);
}
#[test]
fn test_format_str_arg_long_string() {
let long_str = "a".repeat(60);
let result = LogFormat::format_str_arg(&long_str);
assert!(result.starts_with("'aaa"));
assert!(result.ends_with("'..."));
}
}