secra-logger 0.3.0

一个生产级的 Rust 日志系统库,基于 tracing 生态系统构建,支持结构化 JSON 日志、文件滚动、UTC+8 时区等特性
# Secra Logger

一个生产级的 Rust 日志系统库,基于 `tracing` 生态系统构建。

## 特性

- **统一日志入口**:对业务代码透明,只需使用 `tracing::info!` 等宏
-**结构化日志(JSON)**:所有输出日志为标准 JSON 格式
-**高可配置性**:日志等级、输出位置、滚动策略可配置
-**上下文感知**:支持 Span / RequestId / 自定义字段注入
-**生产可用**:支持文件滚动、异步写入、标准输出
-**UTC+8 时区**:所有日志时间统一为北京时间

## 快速开始

### 基本使用

```rust
use secra_logger::{init_logging, LogConfig, LogLevel, LogOutput};
use tracing::info;

fn main() {
    let config = LogConfig {
        level: LogLevel::Info,
        output: LogOutput::Stdout,
        json: true,
        ..Default::default()
    };

    init_logging(config).unwrap();

    info!("Hello, world!");
}
```

### 使用环境变量

```rust
use secra_logger::init_from_env;

fn main() {
    init_from_env().unwrap();
    tracing::info!("Hello, world!");
}
```

设置环境变量:
```bash
export RUST_LOG=info
export LOG_FILE=./logs/app.log
export LOG_DAILY=true
export LOG_JSON=true
```

### 使用 Span 注入上下文

```rust
use tracing::{info, info_span};

let span = info_span!(
    "http_request",
    request_id = "req-12345",
    user_id = "user123",
    company_id = "company456"
);
let _enter = span.enter();

info!("处理请求");
```

## 配置选项

### LogConfig

```rust
pub struct LogConfig {
    pub level: LogLevel,              // 全局默认日志等级
    pub modules: HashMap<String, LogLevel>, // 按模块配置日志等级
    pub output: LogOutput,            // 日志输出配置
    pub json: bool,                   // 是否使用 JSON 格式
    pub actix_web: bool,              // 是否启用 Actix-Web 集成
    pub capture_panic: bool,           // 是否捕获 panic 并记录
}
```

### LogOutput

支持三种输出模式:

1. **Stdout**:标准输出
2. **File**:文件输出(支持滚动)
3. **Both**:同时输出到文件和标准输出

```rust
// 文件输出,按天滚动
LogOutput::File {
    path: PathBuf::from("./logs/app.log"),
    max_size: Some(100 * 1024 * 1024), // 100MB
    daily: true,
    max_files: Some(7), // 保留 7 天
}
```

## 日志格式

所有日志输出为 JSON 格式,包含以下字段:

```json
{
  "timestamp": "2025-01-01T12:00:00.123+08:00",
  "level": "INFO",
  "target": "my_crate::module",
  "message": "something happened",
  "span": {
    "request_id": "uuid",
    "user_id": "optional",
    "company_id": "optional"
  }
}
```

## 环境变量

- `RUST_LOG`:日志级别(如 `info`, `debug`, `my_crate=debug`- `LOG_FILE`:日志文件路径
- `LOG_MAX_SIZE`:最大文件大小(字节)
- `LOG_DAILY`:是否按天滚动(`true``1`- `LOG_MAX_FILES`:最大保留文件数
- `LOG_STDOUT`:是否同时输出到标准输出(`true``1`- `LOG_JSON`:是否使用 JSON 格式(`true``1`,默认 true)
- `LOG_ACTIX_WEB`:是否启用 Actix-Web 集成(`true``1`
## 示例

查看 `examples/` 目录下的示例:

- `basic.rs`:基本使用
- `file_output.rs`:文件输出配置
- `env_config.rs`:环境变量配置
- `file_deletion_test.rs`:文件删除测试(演示运行过程中删除日志文件后的行为)
- `size_rotation.rs`:日志大小滚动示例(演示当日志文件超过指定大小时如何触发滚动)

运行示例:

```bash
cargo run --example basic
cargo run --example file_output
RUST_LOG=debug cargo run --example env_config
cargo run --example file_deletion_test
cargo run --example size_rotation
```

## 模块结构

- **config**:日志配置解析与校验
- **formatter**:JSON 格式化逻辑
- **layer**:tracing Layer 组合
- **time**:UTC+8 时间处理
- **init**:日志系统初始化入口

## 注意事项

1. **初始化只能调用一次**:重复初始化会返回错误
2. **文件滚动**:使用 `tracing-appender` 处理文件滚动,支持按天滚动
3. **Panic 捕获**:默认启用 panic hook,自动记录 panic 信息
4. **时区**:所有日志时间统一为 UTC+8(北京时间)
5. **Doctest 环境**:如果在运行示例时看到"日志系统已被其他代码初始化"的警告,这是因为 doctest 在编译时已经初始化了 subscriber。在实际生产环境中,请确保只初始化一次日志系统,配置会正常生效。

### 解决 Doctest 初始化问题

如果在运行示例时遇到初始化警告,这是因为 doctest 在编译时已经初始化了 subscriber。由于 tracing 的设计限制,无法强制替换已存在的 subscriber。

**解决方案**:

1. **使用 `allow_already_initialized` 选项**(仅用于测试/示例):
   ```rust
   let config = LogConfig {
       // ... 其他配置
       allow_already_initialized: true, // 允许在已初始化时继续
       ..Default::default()
   };
   ```
   注意:即使设置了此选项,配置也可能不会生效,因为会使用已存在的 subscriber。

2. **在生产环境中**:确保在程序开始时只初始化一次日志系统,这样所有配置都会正常生效。

3. **使用独立的测试二进制文件**:创建独立的测试程序,而不是使用示例,避免 doctest 的影响。

4. **在程序开始时初始化**:确保在程序的最开始就初始化日志系统,避免其他代码先初始化。

## License

MIT