statsig_rust/
output_logger.rs

1use log::{debug, error, info, warn, Level};
2
3const MAX_CHARS: usize = 400;
4const TRUNCATED_SUFFIX: &str = "...[TRUNCATED]";
5
6const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Warn;
7
8#[derive(Clone)]
9pub enum LogLevel {
10    None,
11    Debug,
12    Info,
13    Warn,
14    Error,
15}
16
17impl From<&str> for LogLevel {
18    fn from(level: &str) -> Self {
19        match level.to_lowercase().as_str() {
20            "debug" => LogLevel::Debug,
21            "info" => LogLevel::Info,
22            "warn" => LogLevel::Warn,
23            "error" => LogLevel::Error,
24            "none" => LogLevel::None,
25            _ => DEFAULT_LOG_LEVEL,
26        }
27    }
28}
29
30impl From<u32> for LogLevel {
31    fn from(level: u32) -> Self {
32        match level {
33            0 => LogLevel::None,
34            1 => LogLevel::Error,
35            2 => LogLevel::Warn,
36            3 => LogLevel::Info,
37            4 => LogLevel::Debug,
38            _ => DEFAULT_LOG_LEVEL,
39        }
40    }
41}
42
43impl LogLevel {
44    fn to_third_party_level(&self) -> Option<Level> {
45        match self {
46            LogLevel::Debug => Some(Level::Debug),
47            LogLevel::Info => Some(Level::Info),
48            LogLevel::Warn => Some(Level::Warn),
49            LogLevel::Error => Some(Level::Error),
50            LogLevel::None => None,
51        }
52    }
53}
54
55pub fn initialize_simple_output_logger(level: &Option<LogLevel>) {
56    let level = level.as_ref().unwrap_or(&DEFAULT_LOG_LEVEL).clone();
57
58    let final_level = match level {
59        LogLevel::None => {
60            return;
61        }
62        _ => match level.to_third_party_level() {
63            Some(level) => level,
64            None => return,
65        },
66    };
67
68    match simple_logger::init_with_level(final_level) {
69        Ok(()) => {}
70        Err(_) => {
71            log::set_max_level(final_level.to_level_filter());
72        }
73    }
74}
75
76pub fn log_message(tag: &str, level: LogLevel, msg: String) {
77    let truncated_msg = if msg.chars().count() > MAX_CHARS {
78        let visible_chars = MAX_CHARS.saturating_sub(TRUNCATED_SUFFIX.len());
79        format!(
80            "{}{}",
81            msg.chars().take(visible_chars).collect::<String>(),
82            TRUNCATED_SUFFIX
83        )
84    } else {
85        msg
86    };
87
88    if let Some(level) = level.to_third_party_level() {
89        match level {
90            Level::Debug => debug!("[Statsig.{}] {}", tag, truncated_msg),
91            Level::Info => info!("[Statsig.{}] {}", tag, truncated_msg),
92            Level::Warn => warn!("[Statsig.{}] {}", tag, truncated_msg),
93            Level::Error => error!("[Statsig.{}] {}", tag, truncated_msg),
94            _ => {}
95        };
96    }
97}
98
99#[macro_export]
100macro_rules! log_d {
101  ($tag:expr, $($arg:tt)*) => {
102        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Debug, format!($($arg)*))
103    }
104}
105
106#[macro_export]
107macro_rules! log_i {
108  ($tag:expr, $($arg:tt)*) => {
109        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Info, format!($($arg)*))
110    }
111}
112
113#[macro_export]
114macro_rules! log_w {
115  ($tag:expr, $($arg:tt)*) => {
116        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Warn, format!($($arg)*))
117    }
118}
119
120#[macro_export]
121macro_rules! log_e {
122  ($tag:expr, $($arg:tt)*) => {
123        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Error, format!($($arg)*))
124    }
125}
126
127#[macro_export]
128macro_rules! log_error_to_statsig_and_console {
129  ($ops_stats:expr, $tag:expr, $($arg:tt)*) => {
130    let err_message = format!($($arg)*);
131    let event = ErrorBoundaryEvent {
132        exception: err_message.clone(),
133        tag: $tag.to_string(),
134        extra: None,
135    };
136    $ops_stats.log_error(event);
137
138    $crate::output_logger::log_message(&$tag, $crate::output_logger::LogLevel::Error, err_message)
139  }
140}