ruwebframe 0.1.7

a simple webframe for rust actix-web, based on rudi and rbatis.
Documentation
use flexi_logger::{Cleanup, Criterion, FileSpec, Logger, Naming};
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt::{Debug, Display};

static LOG_CONFIGS: OnceLock<HashMap<&'static str, String>> = OnceLock::new();

fn get_base(ltype: &str) -> String {
    ltype.to_string()
}

#[derive(Debug, Clone)]
pub struct RuLog {}

impl ruentity::BaseEntitySingle for RuLog {}
impl RuLog {
    pub fn new() -> RuLog {
        get_log_info();
        RuLog {}
    }
}
impl RuLog {
    pub fn info(&self, msg: &str) {
        println!("{}", msg);
    }
}

use crate::rubase::{BaseEntity, ruentity};
use crate::rulog;
use flexi_logger::FlexiLoggerError::LevelFilter;
use flexi_logger::LoggerHandle;
use log::Level;

use crate::rubase::rutils::{json_utils, struct2jsonpretty};
use serde::Serialize;
use serde_json::Value;
use std::sync::OnceLock;

// 存储所有 logger 实例
static LOGGERS: OnceLock<HashMap<String, LoggerHandle>> = OnceLock::new();

// 初始化所有日志配置
fn init_loggers() -> &'static HashMap<String, LoggerHandle> {
    LOGGERS.get_or_init(|| {
        let mut map = HashMap::new();

        // 为每个日志类型创建独立的 logger
        for ltype in &["db", "info", "error"] {
            let handle = create_logger(ltype);
            map.insert(ltype.to_string(), handle);
        }

        map
    })
}

// 创建单个 logger
fn create_logger(ltype: &str) -> LoggerHandle {
    // 根据类型设置不同的日志级别
    let log_level = match ltype {
        "db" => "info", // db 记录 info 及以上
        "info" => "info",
        "error" => "error", // error 只记录 error
        _ => "info",
    };

    Logger::try_with_str(log_level)
        .unwrap()
        .log_to_file(
            FileSpec::default()
                .directory("./logs")
                .basename(ltype) // 文件名前缀:db, info, error
                .suppress_timestamp()
                .suffix(".log"),
        )
        .append()
        .format(|w, now, record| {
            // 统一格式:[2026-08-16 14:30:25.123] [INFO] module:10 - message
            write!(
                w,
                "[{}] [{}] {}:{} - {}",
                now.format("%Y-%m-%d %H:%M:%S%.3f"),
                record.level(),
                record.module_path().unwrap_or("unknown"),
                record.line().unwrap_or(0),
                record.args()
            )
        })
        .rotate(
            Criterion::Size(50_000_000), // 50 MB 轮转
            Naming::Numbers,             // 数字编号:db.0.log, db.1.log...
            Cleanup::KeepLogFiles(5),    // 保留最近 5 个
        )
        .start()
        .unwrap()
}

// 获取 logger 实例
pub fn get_log(ltype: &str) -> Option<&'static LoggerHandle> {
    let loggers = init_loggers();
    loggers.get(ltype)
}

// 获取日志文件的基础名称
pub fn get_base1(ltype: &str) -> String {
    ltype.to_string()
}
static CONFIG: OnceLock<String> = OnceLock::new();
fn get_log_db() -> &'static String {
    get_log_config("db")
}
fn get_log_info() -> &'static String {
    get_log_config("info")
}
fn get_log_error() -> &'static String {
    get_log_config("error")
}
fn get_basename(ltype: &str) -> String {
    // let mut basename = "app";
    // if ltype == "error" {
    //     basename = "app-err";
    // } else if ltype == "db" {
    //     basename = "app-db";
    // }
    //
    // basename.to_string()
    "app".to_string()
}
fn get_log_config(ltype: &str) -> &'static String {
    CONFIG.get_or_init(|| {
        let _r = Logger::try_with_str(ltype)
            .unwrap()
            .log_to_file(
                FileSpec::default()
                    .directory("./logs") // 指定文件夹
                    .basename(get_basename(ltype)) // 指定文件名前缀
                    .suppress_timestamp()
                    .suffix(".log"), // 指定文件后缀
            )
            .append()
            .format(|w, now, record| {
                // 格式:[2026-08-01 14:30:25.123] [INFO] my_module:10 - message
                write!(
                    w,
                    "[{}] [{}] {}:{} - {}",
                    now.format("%Y-%m-%d %H:%M:%S%.3f"),
                    record.level(),
                    record.module_path().unwrap_or("unknown"),
                    record.line().unwrap_or(0),
                    record.args()
                )
            })
            .rotate(
                Criterion::Size(50_000_000), // 当文件达到 50 MB 时触发轮转[citation:3][citation:5][citation:6]
                Naming::Numbers,             // 旧文件使用数字编号命名
                Cleanup::KeepLogFiles(5),    // 只保留最近的 5 个日志文件[citation:8][citation:10]
            )
            .start();

        return String::from("init log");
    })
}

pub fn info(msg0: impl Debug) -> () {
    get_log_info();
    let msg = format!("{:#?}", msg0);
    println!("{}", msg);
    log::info!("{}", msg)
}
pub fn error(msg: impl Debug) {
    get_log_error();
    let msg = format!("{:#?}", msg);
    println!("{}", msg);
    log::error!("{}", msg)
}
pub fn db(msg: impl Debug) {
    get_log_db();
    let msg = format!("{:#?}", msg);
    println!("{}", msg);
    log::debug!("{}", msg)
}

pub fn debug(msg: impl Debug) {
    get_log_info();
    let msg = format!("{:#?}", msg);
    println!("{}", msg);
    log::debug!("{}", msg)
}

#[allow(unused)]
macro_rules! info {
    ($($arg:tt)*) => {
        println!("{}", format!($($arg)*));
        log::info!("{}", format!($($arg)*));
    };
}
pub fn info2(msg1: impl Debug, msg2: impl Debug) -> () {
    rulog::find_bean_ru_log();
    let mut msg = format!("{:#?} {:#?}", msg1, msg2);

    println!("{}", msg);
    log::info!("{}", msg);
}
pub fn error2(msg1: &str, msg2: impl Debug) -> () {
    get_log_error();
    let msg = format!("{} {:#?}", msg1, msg2);

    println!("{}", msg);
    log::error!("{}", msg);
}
pub fn debug2(msg1: &str, msg2: impl Debug) -> () {
    rulog::find_bean_ru_log();
    let msg = format!("{} {:#?}", msg1, msg2);

    println!("{}", msg);
    log::debug!("{}", msg);
}
pub fn db2(msg1: &str, msg2: impl Debug) -> () {
    get_log_db();
    let msg = format!("{} {:#?}", msg1, msg2);

    println!("{}", msg);
    log::error!("{}", msg);
}