Rust结构化日志库structured-logger的使用,高效记录和管理应用程序日志的Rust插件库

Rust结构化日志库structured-logger的使用,高效记录和管理应用程序日志的Rust插件库

概述

structured-logger是一个用于log crate的日志记录实现,可以同步或异步地记录结构化值,以JSON、CBOR或其他格式输出到文件、stderr、stdout或其他目的地。它受到了std-logger的启发。

示例代码

以下是内容中提供的简单示例:

use serde::Serialize;
use structured_logger::{async_json::new_writer, unix_ms, Builder};

#[tokio::main]
async fn main() {
    // 初始化日志记录器
    Builder::with_level("info")
        .with_target_writer("*", new_writer(tokio::io::stdout()))
        .init();

    // 或者使用默认配置:
    // structured_logger::init();

    let kv = ContextLog {
        uid: "user123".to_string(),
        action: "upate_book".to_string(),
    };

    log::info!("hello world");
    // 这个日志会输出到stdout:
    // {"level":"INFO","message":"hello world","target":"simple","timestamp":1679745592127}

    log::info!(target: "api",
        method = "GET",
        path = "/hello",
        status = 200_u16,
        start = unix_ms(),
        elapsed = 10_u64,
        kv:serde = kv;
        "",
    );
    // 这个日志会输出到stdout:
    // {"elapsed":10,"kv":{"uid":"user123","action":"upate_book"},"level":"INFO","message":"","method":"GET","path":"/hello","start":1679745592127,"status":200,"target":"api","timestamp":1679745592127}
}

#[derive(Serialize)]
struct ContextLog {
    uid: String,
    action: String,
}

完整示例

基于上述内容,这里提供一个更完整的示例:

use serde::Serialize;
use structured_logger::{async_json::new_writer, unix_ms, Builder};
use tokio::fs::File;

#[derive(Serialize)]
struct UserActivity {
    user_id: String,
    action: String,
    duration_ms: u64,
}

#[tokio::main]
async fn main() {
    // 初始化日志记录器,同时输出到stdout和文件
    let log_file = File::create("app.log").await.unwrap();
    
    Builder::with_level("info")
        // 所有日志目标都输出到stdout
        .with_target_writer("*", new_writer(tokio::io::stdout()))
        // 仅api目标的日志输出到文件
        .with_target_writer("api", new_writer(log_file))
        .init();

    // 模拟用户活动
    let activity = UserActivity {
        user_id: "user_789".to_string(),
        action: "view_profile".to_string(),
        duration_ms: 125,
    };

    // 普通日志消息
    log::info!("Application started");
    
    // 带有结构化数据的API访问日志
    log::info!(
        target: "api",
        method = "POST",
        path = "/api/user",
        status = 201_u16,
        processing_time = 45_u64,
        user_activity:serde = activity;
        "User profile accessed"
    );

    // 错误日志示例
    log::error!(
        target: "auth",
        user_id = "user_789",
        error_code = "AUTH_403",
        ip = "192.168.1.100";
        "Unauthorized access attempt"
    );
}

特性

  1. 结构化日志记录:支持以结构化格式(如JSON)记录日志,便于后续处理和分析
  2. 多种输出目标:可以输出到stdout、stderr、文件或其他自定义目标
  3. 异步支持:提供异步日志记录能力,减少对应用程序性能的影响
  4. 灵活配置:可以根据日志目标(target)设置不同的输出方式和格式
  5. 自定义字段:支持添加任意数量的自定义字段到日志记录中

安装

将以下内容添加到你的Cargo.toml文件中:

[dependencies]
structured-logger = "1.0.4"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }

许可证

该项目采用双重许可证:

  • MIT许可证
  • Apache-2.0许可证

你可以根据需求选择其中一种。


1 回复

Rust结构化日志库structured-logger使用指南

介绍

structured-logger是一个Rust的结构化日志记录库,它提供了高效、灵活的日志记录功能,特别适合需要结构化日志输出的应用程序。与传统的文本日志不同,结构化日志以键值对的形式记录数据,便于后续的日志分析和处理。

主要特性

  • 支持结构化日志记录
  • 高性能日志记录
  • 可定制的日志格式
  • 支持异步日志记录
  • 多种日志级别控制
  • 易于与现有日志系统集成

安装

在Cargo.toml中添加依赖:

[dependencies]
structured-logger = "0.4"
log = "0.4"

基本使用方法

1. 初始化日志记录器

use structured_logger::{async_json::new_writer, Builder};
use log::LevelFilter;

fn init_logger() {
    // 使用Builder创建日志记录器,设置日志级别为Info
    // 将所有目标的日志输出到标准输出(stdout)
    Builder::with_level(LevelFilter::Info)
        .with_target_writer("*", new_writer(std::io::stdout()))
        .init();
}

2. 记录日志

use log::{info, warn, error};

fn main() {
    // 初始化日志记录器
    init_logger();
    
    // 记录结构化日志
    info!(target: "my_app",
        event = "startup",  // 自定义字段
        version = env!("CARGO_PKG_VERSION"),  // 获取Cargo版本号
        "Application starting");  // 日志消息
    
    // 记录警告日志
    warn!(
        user_id = 12345,
        action = "login",
        "User attempted login with expired token"
    );
    
    // 记录错误日志
    error!(
        error = "Database connection failed",
        retry_count = 3,
        "Critical operation failed"
    );
}

3. 输出示例

上述代码会产生类似如下的结构化日志:

{
  "timestamp": "2023-05-15T12:34:56.789Z",
  "level": "INFO",
  "target": "my_app",
  "message": "Application starting",
  "event": "startup",
  "version": "1.0.0"
}

{
  "timestamp": "2023-05-15T12:34:56.790Z",
  "level": "WARN",
  "message": "User attempted login with expired token",
  "user_id": 12345,
  "action": "login"
}

高级用法

自定义日志格式

use structured_logger::{Builder, unix_ms};

fn init_custom_logger() {
    // 创建自定义格式的日志记录器
    Builder::with_level("info")
        .with_default_writer(|_| {
            Box::new(|record| {
                // 自定义日志格式:[时间戳][日志级别][目标] 键值对 - 消息
                println!(
                    "[{}][{}][{}] {} - {}",
                    unix_ms(),  // 获取当前UNIX时间戳(毫秒)
                    record.level(),  // 日志级别
                    record.target(),  // 日志目标
                    record.key_values(),  // 键值对
                    record.args()  // 日志消息
                );
            })
        })
        .init();
}

异步日志记录

use structured_logger::{async_json::new_writer, Builder};
use log::LevelFilter;

#[tokio::main]
async fn main() {
    // 使用异步日志记录器,输出到标准输出
    Builder::with_level(LevelFilter::Info)
        .with_target_writer("*", new_writer(tokio::io::stdout()))
        .init();
    
    // 异步记录日志
    log::info!("This log will be written asynchronously");
}

文件日志记录

use structured_logger::{async_json::new_writer, Builder};
use log::LevelFilter;
use std::fs::File;

fn init_file_logger() {
    // 创建日志文件
    let file = File::create("app.log").expect("Failed to create log file");
    
    // 初始化文件日志记录器
    Builder::with_level(LevelFilter::Info)
        .with_target_writer("*", new_writer(file))
        .init();
}

性能建议

  1. 对于高性能应用,使用异步日志记录
  2. 避免在日志宏中执行复杂计算
  3. 在生产环境中适当调整日志级别
  4. 考虑使用缓冲写入器减少I/O操作

与其他日志系统的集成

structured-logger可以与log生态系统中的其他工具一起使用:

use env_logger;
use structured_logger;

fn init_combined_logger() {
    // 初始化env_logger用于开发环境
    env_logger::init();
    
    // 初始化structured_logger用于生产环境
    structured_logger::Builder::with_level("info")
        .with_default_writer(structured_logger::json::new_writer(std::io::stdout()))
        .init_quiet();
}

完整示例Demo

下面是一个完整的应用程序示例,展示了如何使用structured-logger记录不同类型的日志:

use structured_logger::{async_json::new_writer, Builder};
use log::{info, warn, error, debug};
use std::time::Duration;
use std::thread;

fn init_logger() {
    // 初始化日志记录器,设置日志级别为Debug
    Builder::with_level(log::LevelFilter::Debug)
        .with_target_writer("*", new_writer(std::io::stdout()))
        .init();
}

fn perform_operation(user_id: u64) -> Result<(), String> {
    // 模拟一些业务逻辑
    if user_id % 2 == 0 {
        Ok(())
    } else {
        Err("Operation failed for odd user ID".to_string())
    }
}

fn main() {
    // 初始化日志系统
    init_logger();
    
    info!(
        target: "app_startup",
        version = env!("CARGO_PKG_VERSION"),
        "Starting application"
    );
    
    // 模拟用户操作
    for user_id in 1..=5 {
        debug!(
            user_id = user_id,
            "Processing user request"
        );
        
        thread::sleep(Duration::from_millis(100));
        
        match perform_operation(user_id) {
            Ok(_) => info!(
                user_id = user_id,
                status = "success",
                "Operation completed"
            ),
            Err(e) => error!(
                user_id = user_id,
                status = "failed",
                error = e,
                "Operation failed"
            ),
        }
    }
    
    warn!(
        notice = "shutdown",
        "Application shutting down"
    );
}

输出示例:

{
  "timestamp": "2023-05-15T12:34:56.789Z",
  "level": "INFO",
  "target": "app_startup",
  "message": "Starting application",
  "version": "1.0.0"
}
{
  "timestamp": "2023-05-15T12:34:56.790Z",
  "level": "DEBUG",
  "message": "Processing user request",
  "user_id": 1
}
{
  "timestamp": "2023-05-15T12:34:56.890Z",
  "level": "ERROR",
  "message": "Operation failed",
  "user_id": 1,
  "status": "failed",
  "error": "Operation failed for odd user ID"
}
{
  "timestamp": "2023-05-15T12:34:56.890Z",
  "level": "DEBUG",
  "message": "Processing user request",
  "user_id": 2
}
{
  "timestamp": "2023-05-15T12:34:56.990Z",
  "level": "INFO",
  "message": "Operation completed",
  "user_id": 2,
  "status": "success"
}
{
  "timestamp": "2023-05-15T12:34:57.090Z",
  "level": "WARN",
  "message": "Application shutting down",
  "notice": "shutdown"
}

structured-logger是一个强大而灵活的工具,特别适合需要结构化日志的现代应用程序。通过键值对的形式记录日志数据,可以大大简化日志分析和监控的复杂度。

回到顶部