cfun 0.2.11

Tidy up common functions
Documentation
#[cfg(feature = "log")]
use tracing::level_filters::LevelFilter;
#[cfg(feature = "log")]
use tracing_appender::rolling::{RollingFileAppender, Rotation};
#[cfg(feature = "log")]
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, Layer};

#[cfg(feature = "log")]
pub enum CLogLevel {
    Trace,
    Debug,
    Info,
    Warn,
    Error,
}

#[cfg(feature = "log")]
pub use tracing::{debug, error, info, trace, warn};

#[cfg(feature = "log")]
fn from_cloglevel(level: &CLogLevel) -> LevelFilter {
    match level {
        CLogLevel::Trace => LevelFilter::TRACE,
        CLogLevel::Debug => LevelFilter::DEBUG,
        CLogLevel::Info => LevelFilter::INFO,
        CLogLevel::Warn => LevelFilter::WARN,
        CLogLevel::Error => LevelFilter::ERROR,
    }
}

/// only log to console
#[cfg(feature = "log")]
pub fn default_console_log(log_level: CLogLevel) {
    let timer = tracing_subscriber::fmt::time::ChronoLocal::new("%Y-%m-%d %H:%M:%S".to_owned());
    let console_layer = tracing_subscriber::fmt::layer()
        .with_timer(timer.clone())
        .with_target(true)
        .with_line_number(true)
        .with_writer(std::io::stdout)
        .with_ansi(true)
        .with_filter(from_cloglevel(&log_level));
    tracing_subscriber::registry().with(console_layer).init();
}

/// 使用宏来减少重复代码,提高代码的可维护性
#[cfg(feature = "log")]
macro_rules! define_console_log_functions {
    ($($name:ident, $level:ident);* $(;)?) => {
        $(
            /// default level log to console
            #[cfg(feature = "log")]
            pub fn $name() {
                default_console_log(CLogLevel::$level);
            }
        )*
    };
}

// 调用宏来定义各个日志级别对应的函数
#[cfg(feature = "log")]
define_console_log_functions! {
    dcl_info, Info;
    dcl_debug, Debug;
    dcl_trace, Trace;
    dcl_warn, Warn;
    dcl_error, Error;
}

/// only log to file
#[cfg(feature = "log")]
pub fn default_file_log(
    log_level: CLogLevel,
    log_path: &str,
    log_file_name: &str,
    max_log_files: Option<usize>,
) {
    let timer = tracing_subscriber::fmt::time::ChronoLocal::new("%Y-%m-%d %H:%M:%S".to_owned());

    let mut file_appender = RollingFileAppender::builder()
        .rotation(Rotation::DAILY)
        .filename_prefix(log_file_name)
        .filename_suffix("log");

    if let Some(max_log_files) = max_log_files {
        file_appender = file_appender.max_log_files(max_log_files);
    };
    let file_appender = file_appender.build(log_path).unwrap();

    let file_layer = tracing_subscriber::fmt::layer()
        .with_timer(timer)
        .with_target(true)
        .with_line_number(true)
        .with_ansi(false)
        .with_writer(file_appender)
        .with_filter(from_cloglevel(&log_level));
    tracing_subscriber::registry().with(file_layer).init();
}

/// log to console and file
#[cfg(feature = "log")]
pub fn default_log(
    log_level: CLogLevel,
    log_path: &str,
    log_file_name: &str,
    max_log_files: Option<usize>,
) {
    let timer = tracing_subscriber::fmt::time::ChronoLocal::new("%Y-%m-%d %H:%M:%S".to_owned());
    let console_layer = tracing_subscriber::fmt::layer()
        .with_timer(timer.clone())
        .with_target(true)
        .with_line_number(true)
        .with_writer(std::io::stdout)
        .with_ansi(true)
        .with_filter(from_cloglevel(&log_level));

    let mut file_appender = RollingFileAppender::builder()
        .rotation(Rotation::DAILY)
        .filename_prefix(log_file_name)
        .filename_suffix("log");

    if let Some(max_log_files) = max_log_files {
        file_appender = file_appender.max_log_files(max_log_files);
    };
    let file_appender = file_appender.build(log_path).unwrap();

    let file_layer = tracing_subscriber::fmt::layer()
        .with_timer(timer)
        .with_target(true)
        .with_line_number(true)
        .with_ansi(false)
        .with_writer(file_appender)
        .with_filter(from_cloglevel(&log_level));
    tracing_subscriber::registry()
        .with(file_layer)
        .with(console_layer)
        .init();
}

#[test]
#[cfg(feature = "log")]
fn test_console_log() {
    default_console_log(CLogLevel::Trace);
    tracing::trace!("trace");
    tracing::debug!("debug");
    tracing::info!("info");
    tracing::warn!("warn");
    tracing::error!("error");
}

#[test]
#[cfg(feature = "log")]
fn test_file_log() {
    default_file_log(CLogLevel::Trace, "./", "test", None);
    tracing::trace!("trace");
    tracing::debug!("debug");
    tracing::info!("info");
    tracing::warn!("warn");
    tracing::error!("error");
}

#[test]
#[cfg(feature = "log")]
fn test_log() {
    default_log(CLogLevel::Trace, "./", "test", None);
    tracing::trace!("trace");
    tracing::debug!("debug");
    tracing::info!("info");
    tracing::warn!("warn");
    tracing::error!("error");
}