rust 一个日志缓存记录的通用实现方法

 更新时间:2024年04月02日 10:20:33   作者:会编程的大白熊  
本文给出了一个通用的设计模式,通过建造者模式实例化记录对象,可自定义格式化器将实例化后的记录对象写入到指定的缓存对象中,这篇文章主要介绍了rust 一个日志缓存记录的通用实现方法,需要的朋友可以参考下

本文给出了一个通用的设计模式,通过建造者模式实例化记录对象,可自定义格式化器将实例化后的记录对象写入到指定的缓存对象中。

定义记录对象

use chrono::prelude::*;
use std::{
    cell::RefCell, ffi::OsStr, fmt, io, io::Write, path::Path, rc::Rc, str,
    time::SystemTime,
};
const DATETIME_FORMAT: &str = "%Y-%m-%d %H:%M:%S";
/// 将 SystemTime 格式的时间转换为指定格式的字符串
fn format_system_time(st: SystemTime) -> String {
    let local_datetime: DateTime<Local> = st.clone().into();
    local_datetime.format(DATETIME_FORMAT).to_string()
}
/// 定义需要构造的协议
#[derive(Debug, Default, Clone)]
struct Record<'a> {
    event_time: Option<SystemTime>,
    var_a: Option<String>,
    var_b: Option<&'a Path>,
    var_c: Option<i32>,
    var_d: Option<&'a OsStr>,
}
/// Record -> RecordBuilder
impl<'a> Record<'a> {
    /// Returns a new builder.
    #[inline]
    fn builder() -> RecordBuilder<'a> {
        RecordBuilder::new()
    }
    #[inline]
    fn event_time(&self) -> Option<SystemTime> {
        self.event_time
    }
    #[inline]
    fn var_a(&self) -> &Option<String> {
        &self.var_a
    }
    #[inline]
    fn var_b(&self) -> Option<&'a Path> {
        self.var_b
    }
    #[inline]
    fn var_c(&self) -> Option<i32> {
        self.var_c
    }
    #[inline]
    fn var_d(&self) -> Option<&'a OsStr> {
        self.var_d
    }
}

定义对象的建造者

用于根据需求创建不同的记录对象

/// 用于构造协议,通过 Record 和 RecordBuidler 将协议的读写分离
#[derive(Debug)]
struct RecordBuilder<'a> {
    record: Record<'a>,
}
impl<'a> RecordBuilder<'a> {
    /// Construct new `RecordBuilder`.
    #[inline]
    fn new() -> RecordBuilder<'a> {
        RecordBuilder { record: Record::default() }
    }
    #[inline]
    fn event_time(
        &mut self,
        event_time: Option<SystemTime>,
    ) -> &mut RecordBuilder<'a> {
        self.record.event_time = event_time;
        self
    }
    #[inline]
    fn var_a(&mut self, var_a: Option<String>) -> &mut RecordBuilder<'a> {
        self.record.var_a = var_a;
        self
    }
    #[inline]
    fn var_b(&mut self, var_b: Option<&'a Path>) -> &mut RecordBuilder<'a> {
        self.record.var_b = var_b;
        self
    }
    #[inline]
    fn var_c(&mut self, var_c: Option<i32>) -> &mut RecordBuilder<'a> {
        self.record.var_c = var_c;
        self
    }
    #[inline]
    fn var_d(&mut self, var_d: Option<&'a OsStr>) -> &mut RecordBuilder<'a> {
        self.record.var_d = var_d;
        self
    }
    /// Invoke the builder and return a `Record`
    #[inline]
    fn build(&mut self) -> Record<'a> {
        // todo 添加业务逻辑
        self.record.clone()
    }
}
impl<'a> Default for RecordBuilder<'a> {
    fn default() -> Self {
        Self::new()
    }
}

定义写缓存对象

指定记录对象的写入缓存

/// 定义一个写缓存
#[derive(Debug)]
struct Buffer(Vec<u8>);
impl Buffer {
    /// 初始化缓存
    fn new() -> Self {
        Self(vec![])
    }
    /// 清空缓存
    fn clear(&mut self) {
        self.0.clear();
    }
    /// 写缓存
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.extend(buf);
        Ok(buf.len())
    }
    /// 刷新缓存
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
    /// 获得缓存的内容
    fn bytes(&self) -> &[u8] {
        &self.0
    }
}
impl Default for Buffer {
    fn default() -> Self {
        Self::new()
    }
}

定义用于格式化器的写缓存

不同的格式化器可以使用不同的缓存,这里使用上面定义的一个简单的数组缓存来实现格式化器需要的缓存。

/// 定义缓存内容的格式器
struct FormatterBuffer {
    buf: Rc<RefCell<Buffer>>, // RefCell可以修改buf,Rc可以避免使用作用域标识
}
impl FormatterBuffer {
    fn new(buffer: Rc<RefCell<Buffer>>) -> Self {
        FormatterBuffer { buf: buffer }
    }
    fn clear(&mut self) {
        self.buf.borrow_mut().clear()
    }
    fn buf(&self) -> Rc<RefCell<Buffer>> {
        self.buf.clone()
    }
}
impl io::Write for FormatterBuffer {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buf.borrow_mut().write(buf)
    }
    fn flush(&mut self) -> io::Result<()> {
        self.buf.borrow_mut().flush()
    }
}
impl fmt::Debug for FormatterBuffer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("FormatterBuffer").finish()
    }
}

定义格式化器

不同的格式化器将记录转换为不同的格式,写入到缓存中。

#[derive(Debug)]
/// 格式化器
struct Format<'a> {
    buf: &'a mut FormatterBuffer, // 数据缓存
    sep: &'a str,                 // 分隔符
}
impl<'a> Format<'a> {
    /// 写数据到缓存中
    fn write(mut self, record: &Record) -> io::Result<()> {
        let _ = self.write_event_time(record);
        let _ = self.write_var_a(record);
        let _ = self.write_var_b(record);
        let _ = self.write_var_c(record);
        let _ = self.write_var_d(record);
        Ok(())
    }
    fn write_event_time(&mut self, record: &Record) -> io::Result<()> {
        match record.event_time() {
            Some(event_time) => {
                let datetime_str = format_system_time(event_time);
                write!(self.buf, "{}{}", datetime_str, self.sep)
            }
            None => {
                write!(self.buf, "{}", self.sep)
            }
        }
    }
    fn write_var_a(&mut self, record: &Record) -> io::Result<()> {
        match record.var_a() {
            Some(var_a) => {
                write!(self.buf, "{}{}", var_a, self.sep)
            }
            None => write!(self.buf, "{}", self.sep),
        }
    }
    fn write_var_b(&mut self, record: &Record) -> io::Result<()> {
        match record.var_b() {
            Some(var_b) => {
                write!(
                    self.buf,
                    "{}{}",
                    var_b.to_string_lossy(), // 操作系统对路径处理的差异性可能会丢失部分数据
                    self.sep
                )
            }
            None => write!(self.buf, "{}", self.sep),
        }
    }
    fn write_var_c(&mut self, record: &Record) -> io::Result<()> {
        match record.var_c() {
            Some(var_c) => {
                write!(self.buf, "{}{}", var_c, self.sep)
            }
            None => write!(self.buf, "{}", self.sep),
        }
    }
    fn write_var_d(&mut self, record: &Record) -> io::Result<()> {
        match record.var_d() {
            Some(var_d) => {
                write!(
                    self.buf,
                    "{}{}",
                    var_d.to_os_string().to_str().unwrap(), // 操作系统对路径处理的差异性可能会panic
                    self.sep
                )
            }
            None => write!(self.buf, "{}", self.sep),
        }
    }
}

调用示例

fn main() {
    // 创建缓存
    let buffer = Rc::new(RefCell::new(Buffer::default()));
    let mut format_buffer = FormatterBuffer::new(buffer.clone());
    format_buffer.clear();

    // 创建一个格式化器
    let format = Format { buf: &mut format_buffer, sep: "|" };

    // 构造事件发生时间
    let no_timezone =
        NaiveDateTime::parse_from_str("2024-01-02 03:04:05", DATETIME_FORMAT)
            .unwrap();
    let event_time = Local.from_local_datetime(&no_timezone).unwrap().into();
    // 构造路径
    let path = Path::new("./foo/bar.txt");
    let os_str = OsStr::new("1.png");
    // 构造记录
    let record = Record::builder()
        .event_time(Some(event_time))
        .var_a(Some("hello world".to_string()))
        .var_b(Some(path))
        .var_c(Some(999))
        .var_d(Some(os_str))
        .build();

    // 写记录到缓存
    let _ = format.write(&record);

    // 获得RefCell对象的内部值
    let ref_cell_inner_value = buffer.borrow();
    let actual = str::from_utf8(ref_cell_inner_value.bytes()).unwrap();

    let expect = "2024-01-02 03:04:05|hello world|./foo/bar.txt|999|1.png|";
    assert_eq!(actual, expect);
}

参考

https://github.com/rust-cli/env_logger

到此这篇关于rust 一个日志缓存记录的通用实现的文章就介绍到这了,更多相关rust日志缓存内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Rust利用tauri制作个效率小工具

    Rust利用tauri制作个效率小工具

    日常使用电脑中经常会用到一个quicke工具中的轮盘菜单工具。但quicke免费版很多功能不支持,且它的触发逻辑用的不舒服,经常误触。所以本文就来用tauri自制一个小工具,希望对大家有所帮助
    2023-02-02
  • Rust语言数据类型的具体使用

    Rust语言数据类型的具体使用

    在Rust中,每个值都有一个明确的数据类型,本文主要介绍了Rust语言数据类型的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-04-04
  • 一文带你了解Rust是如何处理错误的

    一文带你了解Rust是如何处理错误的

    程序在运行的过程中,总是会不可避免地产生错误,而如何优雅地解决错误,也是语言的设计哲学之一。本文就来和大家来了Rust是如何处理错误的,感兴趣的可以了解一下
    2022-11-11
  • Rust常用特型之Drop特型

    Rust常用特型之Drop特型

    本文主要介绍了Rust常用特型之Drop特型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-03-03
  • Rust语言从入门到精通系列之Iterator迭代器深入详解

    Rust语言从入门到精通系列之Iterator迭代器深入详解

    这篇文章主要为大家介绍了Rust语言从入门到精通系列之Iterator迭代器深入详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • 详解Rust中的变量与常量

    详解Rust中的变量与常量

    大多数尝试过 Rust 的人都希望继续使用它。但是如果你没有使用过它,你可能会想——什么是 Rust,如何理解Rust中的变量与常量,感兴趣的朋友跟随小编一起看看吧
    2022-10-10
  • rust zip异步压缩与解压的代码详解

    rust zip异步压缩与解压的代码详解

    在使用actix-web框架的时候,如果使用zip解压任务将会占用一个工作线程,因为zip库是同步阻塞的,想用异步非阻塞需要用另一个库,下面介绍下rust zip异步压缩与解压的示例,感兴趣的朋友一起看看吧
    2024-04-04
  • Rust 的 into_owned() 方法实例详解

    Rust 的 into_owned() 方法实例详解

    into_owned是Rust语言中std::borrow::Cow 枚举的一个方法,into_owned确保了调用者获得数据的独立所有权,无论Cow之前是引用还是已经拥有数据,本文给大家介绍Rust 的 into_owned() 方法,感兴趣的的朋友跟随小编一起看看吧
    2024-03-03
  • Rust Atomics and Locks内存序Memory Ordering详解

    Rust Atomics and Locks内存序Memory Ordering详解

    这篇文章主要为大家介绍了Rust Atomics and Locks内存序Memory Ordering详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Rust字符串匹配Rabin-Karp算法详解

    Rust字符串匹配Rabin-Karp算法详解

    Rabin-Karp算法也可以叫 Karp-Rabin 算法,它是用来解决多模式串匹配问题的,它的实现方式有点与众不同,首先是计算两个字符串的哈希值,然后通过比较这两个哈希值的大小来判断是否出现匹配,本文详细介绍了字符串匹配Rabin-Karp算法,需要的朋友可以参考下
    2023-05-05

最新评论