ruwebframe 0.1.8

a simple webframe for rust actix-web, based on rudi and rbatis.
Documentation
 

## `rulog` 目录解析


`rulog` 是项目的**日志系统层**,基于 `flexi_logger` + `log` 生态构建,提供控制台输出 + 文件持久化的双通道日志能力,同时封装了日志消息构建器 `LogInfo`。

### 文件结构


```
rulog/
├── mod.rs           # 模块导出
├── rulog.rs         # 核心日志引擎 RuLog + 全局函数
├── rulog_init.rs    # RuLog 的 DI 注册(自动生成)
└── loginfo.rs       # 日志消息构建器 LogInfo
```

---

### 核心设计:双通道日志


[rulog.rs](file:///E:/soft/gitee.com/ruwebframe/src/rulog/rulog.rs) 实现了一个**控制台 + 文件**双通道日志系统:

```
日志调用
    ├──→ println!()  →  控制台输出(即时可见)
    └──→ log::info!() →  flexi_logger → 文件持久化
```

每条日志**同时**输出到控制台和文件,确保开发调试直观、生产环境可追溯。

---

### 日志格式


文件日志的格式为:

```
[2026-08-01 14:30:25.123] [INFO] module::path:10 - 日志消息内容
```

| 字段 | 说明 |
|------|------|
| `时间戳` | 精确到毫秒 `%Y-%m-%d %H:%M:%S%.3f` |
| `日志级别` | INFO / ERROR / DEBUG |
| `模块路径` | Rust 模块路径 `module_path()` |
| `行号` | 源代码行号 `record.line()` |
| `消息` | 日志内容 |

---

### 文件轮转策略


```rust
Logger::try_with_str("info")
    .log_to_file(FileSpec::default()
        .directory("./logs")     // 日志目录
        .basename("app")         // 文件名前缀
        .suffix(".log")          // 后缀
    )
    .rotate(
        Criterion::Size(50_000_000),  // 50MB 触发轮转
        Naming::Numbers,              // 旧文件编号:app_r00001.log
        Cleanup::KeepLogFiles(5),     // 只保留最近 5 个文件
    )
```

| 参数 || 说明 |
|------|-----|------|
| 日志目录 | `./logs/` | 相对路径 |
| 文件名 | `app.log` | 当前日志文件 |
| 轮转大小 | 50 MB | 超过后触发轮转 |
| 轮转命名 | 数字编号 | `app_r00001.log``app_r00002.log`... |
| 保留数量 | 5 个 | 超出自动删除旧文件 |

---

### 日志级别


默认级别为 `info`,支持三个级别:

| 级别 | 函数 | 用途 |
|------|------|------|
| `INFO` | `info()` / `info2()` / `info!()` | 一般信息 |
| `ERROR` | `error()` / `error2()` | 错误信息 |
| `DEBUG` | `debug()` / `debug2()` | 调试信息 |

---

### API 分类


#### 1. 全局函数(推荐,无需实例)


```rust
// 单参数日志
rulog::info("服务启动成功");
rulog::error("连接数据库失败");
rulog::debug("调试信息");

// 双参数拼接日志(msg1 + " " + msg2)
rulog::info2("key:", "value");
rulog::error2("错误:", "详细原因");
rulog::debug2("变量:", "当前值");
```

#### 2. `info!` 宏(类似 `format!` 语法)


```rust
rulog::info!("用户 {} 登录成功,IP: {}", username, ip);
```

内部实现:
```rust
macro_rules! info {
    ($($arg:tt)*) => {
        println!("{}", format!($($arg)*));  // 控制台
        log::info!("{}", format!($($arg)*)); // 文件
    };
}
```

#### 3. `RuLog` 实例方法(DI 注入)


```rust
impl RuLog {
    pub fn info(&self, msg: &str) { println!("{}", msg); }
}
```

`RuLog` 实现了 `BaseEntitySingle`,以单例模式注册在 DI 容器中。

---

### 初始化机制


使用 `OnceLock` 保证日志系统**全局只初始化一次**:

```rust
static CONFIG: OnceLock<String> = OnceLock::new();

fn get_log_config() -> &'static String {
    CONFIG.get_or_init(|| {
        // flexi_logger 初始化...
        Logger::try_with_str("info").unwrap()...
        String::from("init log")
    })
}
```

每次调用 `info()` / `error()` / `debug()` 时,内部先调用 `get_log_config()`,首次调用完成初始化,后续调用直接返回,零开销。

---

### `LogInfo` — 日志消息构建器


[loginfo.rs](file:///E:/soft/gitee.com/ruwebframe/src/rulog/loginfo.rs) 提供了一个**可拼接的日志消息构建器**:

```rust
pub struct LogInfo {
    content: Vec<u8>,  // 字节缓冲区
}
```

| 方法 | 说明 |
|------|------|
| `new()` | 创建空构建器 |
| `new_msg(msg)` | 创建并填充消息 |
| `extend(msg)` | 追加消息(链式调用) |
| `to_string_lossy()` | 转为 `String` |
| `merge_multiple(logs, sep)` | 合并多个 `LogInfo` |

使用示例:
```rust
let log = LogInfo::new_msg("错误代码: ")
    .extend("500")
    .extend(", 原因: ")
    .extend("连接超时");
    
rulog::info(log.to_string_lossy().as_str());
// 输出: "错误代码: 500, 原因: 连接超时"
```

---

### DI 注册


```rust
// 单例模式
direg::register_singleton(SINGLE_BEAN_NAME, RuLog::new);
```

获取方式:`rulog::find_bean_rulog().unwrap()`

但在实际使用中,更推荐直接调用全局函数(`rulog::info()` 等),无需手动获取实例。

---

### 架构定位


```
┌─────────────────────────────────────────────┐
│                 rulog (日志层)                 │
│                                               │
│  ┌──────────────────────────────────────┐    │
│  │  RuLog (单例)                         │    │
│  │  - info() / error() / debug()        │    │
│  └──────────────────────────────────────┘    │
│                                               │
│  ┌──────────────────────────────────────┐    │
│  │  全局函数(推荐使用)                   │    │
│  │  - info()  / info2()  / info!()      │    │
│  │  - error() / error2()                │    │
│  │  - debug() / debug2()                │    │
│  └──────────────┬───────────────────────┘    │
│                 │                              │
│  ┌──────────────┴───────────────────────┐    │
│  │  双通道输出                            │    │
│  │  ┌──────────┐    ┌────────────────┐  │    │
│  │  │println!()│    │ flexi_logger   │  │    │
│  │  │ 控制台    │    │ ./logs/app.log │  │    │
│  │  └──────────┘    │ 轮转/压缩/清理  │  │    │
│  │                  └────────────────┘  │    │
│  └──────────────────────────────────────┘    │
│                                               │
│  ┌──────────────────────────────────────┐    │
│  │  LogInfo (消息构建器)                  │    │
│  │  - new_msg() / extend() / merge()   │    │
│  └──────────────────────────────────────┘    │
└─────────────────────────────────────────────┘
         ↑ 被所有模块依赖
    ┌────┴────┬────────┬────────┬──────┐
    │ rubase  │ rucfg  │ rucmd  │ ...  │
    └─────────┴────────┴────────┴──────┘
```

---

### 快速参考


```rust
// 简单日志
rulog::info("服务启动");

// 键值对日志
rulog::info2("port:", "8080");

// 格式化日志
rulog::info!("第 {} 次重试,延迟 {}ms", retry, delay);

// 错误日志
rulog::error2("数据库错误:", err.to_string().as_str());

// 调试日志
rulog::debug2("request_id:", "abc-123");
```

**总结**:`rulog` 是一个轻量但完整的日志系统,通过 `flexi_logger` 实现文件日志的格式化、轮转和清理,同时保留控制台即时输出。全局函数 API 简洁易用,`OnceLock` 保证初始化安全,`LogInfo` 提供灵活的消息拼接能力。它是整个项目最底层的横切关注点,被所有模块依赖。