secra-logger 0.3.0

一个生产级的 Rust 日志系统库,基于 tracing 生态系统构建,支持结构化 JSON 日志、文件滚动、UTC+8 时区等特性
docs.rs failed to build secra-logger-0.3.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: secra-logger-3.0.3

Secra Logger

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

特性

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

快速开始

基本使用

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!");
}

使用环境变量

use secra_logger::init_from_env;

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

设置环境变量:

export RUST_LOG=info
export LOG_FILE=./logs/app.log
export LOG_DAILY=true
export LOG_JSON=true

使用 Span 注入上下文

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

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:同时输出到文件和标准输出
// 文件输出,按天滚动
LogOutput::File {
    path: PathBuf::from("./logs/app.log"),
    max_size: Some(100 * 1024 * 1024), // 100MB
    daily: true,
    max_files: Some(7), // 保留 7 天
}

日志格式

所有日志输出为 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:是否按天滚动(true1
  • LOG_MAX_FILES:最大保留文件数
  • LOG_STDOUT:是否同时输出到标准输出(true1
  • LOG_JSON:是否使用 JSON 格式(true1,默认 true)
  • LOG_ACTIX_WEB:是否启用 Actix-Web 集成(true1

示例

查看 examples/ 目录下的示例:

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

运行示例:

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 选项(仅用于测试/示例):

    let config = LogConfig {
        // ... 其他配置
        allow_already_initialized: true, // 允许在已初始化时继续
        ..Default::default()
    };
    

    注意:即使设置了此选项,配置也可能不会生效,因为会使用已存在的 subscriber。

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

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

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

License

MIT