sigstat 0.0.3-beta.2

Statsig Rust SDK for usage in multi-user server environments.
Documentation
use log::{debug, error, info, warn, Level};

const MAX_CHARS: usize = 400;
const TRUNCATED_SUFFIX: &str = "...[TRUNCATED]";

const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Warn;

#[derive(Clone)]
pub enum LogLevel {
    None,
    Debug,
    Info,
    Warn,
    Error,
}

impl From<&str> for LogLevel {
    fn from(level: &str) -> Self {
        match level.to_lowercase().as_str() {
            "debug" => LogLevel::Debug,
            "info" => LogLevel::Info,
            "warn" => LogLevel::Warn,
            "error" => LogLevel::Error,
            "none" => LogLevel::None,
            _ => DEFAULT_LOG_LEVEL,
        }
    }
}

impl From<u32> for LogLevel {
    fn from(level: u32) -> Self {
        match level {
            1 => LogLevel::Debug,
            2 => LogLevel::Info,
            3 => LogLevel::Warn,
            4 => LogLevel::Error,
            _ => DEFAULT_LOG_LEVEL,
        }
    }
}

impl LogLevel {
    fn to_third_party_level(&self) -> Option<Level> {
        match self {
            LogLevel::Debug => Some(Level::Debug),
            LogLevel::Info => Some(Level::Info),
            LogLevel::Warn => Some(Level::Warn),
            LogLevel::Error => Some(Level::Error),
            LogLevel::None => None,
        }
    }
}

pub fn initialize_simple_output_logger(level: &Option<LogLevel>) {
    let level = level.as_ref().unwrap_or(&DEFAULT_LOG_LEVEL).clone();

    let final_level = match level {
        LogLevel::None => {
            return;
        }
        _ => match level.to_third_party_level() {
            Some(level) => level,
            None => return,
        },
    };

    match simple_logger::init_with_level(final_level) {
        Ok(_) => {}
        Err(_) => {
            log::set_max_level(final_level.to_level_filter());
        }
    }
}

pub fn log_message(tag: &str, level: LogLevel, msg: String) {
    let truncated_msg = if msg.chars().count() > MAX_CHARS {
        let visible_chars = MAX_CHARS.saturating_sub(TRUNCATED_SUFFIX.len());
        format!(
            "{}{}",
            msg.chars().take(visible_chars).collect::<String>(),
            TRUNCATED_SUFFIX
        )
    } else {
        msg
    };

    if let Some(level) = level.to_third_party_level() {
        match level {
            Level::Debug => debug!("[Statsig.{}] {}", tag, truncated_msg),
            Level::Info => info!("[Statsig.{}] {}", tag, truncated_msg),
            Level::Warn => warn!("[Statsig.{}] {}", tag, truncated_msg),
            Level::Error => error!("[Statsig.{}] {}", tag, truncated_msg),
            _ => {}
        };
    }
}

#[macro_export]
macro_rules! log_d {
  ($tag:expr, $($arg:tt)*) => {
        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Debug, format!($($arg)*))
    }
}

#[macro_export]
macro_rules! log_i {
  ($tag:expr, $($arg:tt)*) => {
        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Info, format!($($arg)*))
    }
}

#[macro_export]
macro_rules! log_w {
  ($tag:expr, $($arg:tt)*) => {
        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Warn, format!($($arg)*))
    }
}

#[macro_export]
macro_rules! log_e {
  ($tag:expr, $($arg:tt)*) => {
        $crate::output_logger::log_message($tag, $crate::output_logger::LogLevel::Error, format!($($arg)*))
    }
}

#[macro_export]
macro_rules! log_error_to_statsig_and_console {
  ($ops_stats:expr, $tag:expr, $($arg:tt)*) => {
    let err_message = format!($($arg)*);
    let event = ErrorBoundaryEvent {
        exception: err_message.clone(),
        tag: $tag.to_string(),
    };
    $ops_stats.log_error(event);

    $crate::output_logger::log_message(&$tag, $crate::output_logger::LogLevel::Error, err_message)
  }
}