log-full 0.0.1

A simple, asynchronous log library
Documentation
//! 日志初始化模块
//! 
//! 提供各种日志初始化函数

use crate::error::{LogError, LogResult};
use crate::logger::{CustomFilter, LogData, LogPlus};
use crate::utils::{AsyncLogType, debug_check_init, parse_level, parse_size};
use crate::quickwit::{QuickwitConfig, QuickwitClient};
use std::io::LineWriter;
use std::path::Path;
use std::sync::{mpsc, OnceLock};

/// 全局日志器实例
static LOGGER_PLUS: OnceLock<LogPlus> = OnceLock::new();

/// 简单初始化日志
#[inline]
pub fn init_log_simple(
    level: &str,
    log_file: String,
    log_file_max: &str,
    use_console: bool,
    use_async: bool,
) -> LogResult<()> {
    init_log_inner(
        parse_level(level)?,
        log_file,
        parse_size(log_file_max)?,
        use_console,
        use_async,
        None,
        None,
    )
}

/// 标准初始化日志
#[inline]
pub fn init_log(
    level: log::LevelFilter,
    log_file: String,
    log_file_max: u32,
    use_console: bool,
    use_async: bool,
) -> LogResult<()> {
    init_log_inner(level, log_file, log_file_max, use_console, use_async, None, None)
}

/// 带插件的初始化日志
#[inline]
pub fn init_log_with_plugin<P>(
    level: log::LevelFilter,
    log_file: String,
    log_file_max: u32,
    use_console: bool,
    use_async: bool,
    plugin: P,
) -> LogResult<()>
where
    P: std::io::Write + Send + Sync + 'static,
{
    init_log_inner(
        level,
        log_file,
        log_file_max,
        use_console,
        use_async,
        Some(Box::new(plugin)),
        None,
    )
}

/// 带过滤器的初始化日志
#[inline]
pub fn init_log_with_filter(
    level: log::LevelFilter,
    log_file: String,
    log_file_max: u32,
    use_console: bool,
    use_async: bool,
    filter: impl CustomFilter,
) -> LogResult<()> {
    init_log_inner(
        level,
        log_file,
        log_file_max,
        use_console,
        use_async,
        None,
        Some(Box::new(filter)),
    )
}

/// 带插件和过滤器的初始化日志
pub fn init_log_with_all<P>(
    level: log::LevelFilter,
    log_file: String,
    log_file_max: u32,
    use_console: bool,
    use_async: bool,
    plugin: P,
    filter: impl CustomFilter,
) -> LogResult<()>
where
    P: std::io::Write + Send + Sync + 'static,
{
    init_log_inner(
        level,
        log_file,
        log_file_max,
        use_console,
        use_async,
        Some(Box::new(plugin)),
        Some(Box::new(filter)),
    )
}

/// 设置特定目标的日志级别
pub fn set_level(target: String, level: log::LevelFilter) {
    if let Ok(mut f) = get_logger_plus().level_filter.write() {
        f.insert(target, level);
    }
}

/// 内部初始化函数
fn init_log_inner(
    level: log::LevelFilter,
    log_file: String,
    log_file_max: u32,
    use_console: bool,
    use_async: bool,
    plugin: Option<Box<dyn std::io::Write + Send + Sync + 'static>>,
    filter: Option<Box<dyn CustomFilter>>,
) -> LogResult<()> {
    init_log_inner_with_config(
        level,
        log_file,
        log_file_max,
        use_console,
        use_async,
        plugin,
        filter,
        true,
        true,
        true,
        Vec::new(),
        None,
    )
}

/// 带完整配置的内部初始化函数
pub fn init_log_inner_with_config(
    level: log::LevelFilter,
    log_file: String,
    log_file_max: u32,
    use_console: bool,
    use_async: bool,
    plugin: Option<Box<dyn std::io::Write + Send + Sync + 'static>>,
    filter: Option<Box<dyn CustomFilter>>,
    show_process_id: bool,
    show_thread_info: bool,
    show_module_path: bool,
    highlight_keywords: Vec<String>,
    quickwit_config: Option<QuickwitConfig>,
) -> LogResult<()> {
    // 验证配置
    if log_file_max == 0 {
        return Err(LogError::config("Max file size cannot be zero"));
    }

    if !log_file.is_empty() {
        if let Some(parent) = Path::new(&log_file).parent() {
            if !parent.exists() {
                return Err(LogError::file_operation(
                    log_file.clone(),
                    "Parent directory does not exist",
                ));
            }
        }
    }

    debug_check_init();

    log::set_max_level(level);

    // 如果启用控制台输出,创建一个控制台共享句柄
    let console = if use_console {
        Some(LineWriter::new(std::io::stdout()))
    } else {
        None
    };

    // 如果启用文件输出,打开日志文件
    let (fileout, log_size) = if !log_file.is_empty() {
        match crate::utils::open_log_file_sync(&log_file) {
            Ok((writer, size)) => (Some(writer), size),
            Err(e) => {
                eprintln!("Failed to open log file {}: {}", log_file, e);
                (None, 0)
            }
        }
    } else {
        (None, 0)
    };

    // 如果启用异步日志,开启一个线程不停读取channel中的数据进行日志写入,属于多生产者单消费者模式
    let sender = if use_async {
        let (sender, receiver) = mpsc::channel::<AsyncLogType>();
        
        // 克隆 Quickwit 客户端配置,用于异步线程
        let quickwit_config_clone = quickwit_config.clone();
        
        std::thread::spawn(move || {
            // 在异步线程中创建 Quickwit 客户端
            let quickwit_client = if let Some(config) = quickwit_config_clone {
                match crate::quickwit::QuickwitClient::new(config) {
                    Ok(client) => {
                        if std::env::var("QUICKWIT_DEBUG").is_ok() {
                            eprintln!("✓ 异步线程中 Quickwit 客户端创建成功");
                        }
                        Some(client)
                    },
                    Err(e) => {
                        eprintln!("✗ 异步线程中 Quickwit 客户端创建失败: {}", e);
                        None
                    }
                }
            } else {
                None
            };
            
            loop {
                match receiver.recv() {
                    Ok(data) => match data {
                        AsyncLogType::Message(msg) => {
                            get_logger_plus().write(&msg);
                            crate::utils::put_msg_to_cache(msg);
                        }
                        AsyncLogType::Flush => get_logger_plus().flush_inner(),
                        AsyncLogType::QuickwitLog(log_entry) => {
                            if let Some(ref client) = quickwit_client {
                                match client.send_log(&log_entry) {
                                    Ok(()) => {
                                        if std::env::var("QUICKWIT_DEBUG").is_ok() {
                                            eprintln!("✓ 异步模式:日志已发送到 Quickwit: {}", log_entry.message);
                                        }
                                    },
                                    Err(e) => {
                                        eprintln!("✗ 异步模式:发送日志到 Quickwit 失败: {}", e);
                                        eprintln!("  日志内容: {}", log_entry.message);
                                        eprintln!("  错误详情: {:?}", e);
                                    }
                                }
                            }
                        }
                    },
                    Err(e) => eprintln!("logger channel recv error: {}", e),
                }
            }
        });
        Some(sender)
    } else {
        None
    };

    let logger_data = LogData {
        log_size,
        console,
        fileout,
        sender,
        plugin,
    };

    // 创建 Quickwit 客户端(如果配置了)
    let quickwit_client = match quickwit_config {
        Some(config) => {
            if std::env::var("QUICKWIT_DEBUG").is_ok() {
                eprintln!("正在创建 Quickwit 客户端,配置: {:?}", config);
            }
            match QuickwitClient::new(config) {
                Ok(client) => {
                    if std::env::var("QUICKWIT_DEBUG").is_ok() {
                        eprintln!("✓ Quickwit 客户端创建成功");
                    }
                    Some(client)
                },
                Err(e) => {
                    eprintln!("✗ Quickwit 客户端创建失败: {}", e);
                    return Err(e);
                }
            }
        },
        None => {
            if std::env::var("QUICKWIT_DEBUG").is_ok() {
                eprintln!("未配置 Quickwit,跳过客户端创建");
            }
            None
        },
    };

    let logger = LogPlus::new(
        level,
        log_file,
        log_file_max,
        filter,
        logger_data,
        show_process_id,
        show_thread_info,
        show_module_path,
        highlight_keywords,
        quickwit_client,
    );

    LOGGER_PLUS
        .set(logger)
        .map_err(|_| LogError::initialization_error("Logger already initialized"))?;

    log::set_logger(get_logger_plus())
        .map_err(|e| LogError::initialization_error(format!("Failed to set logger: {}", e)))?;

    Ok(())
}

/// 获取全局日志器实例
pub fn get_logger_plus() -> &'static LogPlus {
    LOGGER_PLUS.get().expect("Logger not initialized")
}

/// 检查日志器是否已初始化
pub fn is_initialized() -> bool {
    LOGGER_PLUS.get().is_some()
}

/// 获取当前日志级别
pub fn current_log_level() -> Option<log::LevelFilter> {
    LOGGER_PLUS.get().map(|logger| logger.level)
}