rust 一個日志緩存記錄的通用實(shí)現(xiàn)方法
本文給出了一個通用的設(shè)計模式,通過建造者模式實(shí)例化記錄對象,可自定義格式化器將實(shí)例化后的記錄對象寫入到指定的緩存對象中。
定義記錄對象
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 格式的時間轉(zhuǎn)換為指定格式的字符串
fn format_system_time(st: SystemTime) -> String {
let local_datetime: DateTime<Local> = st.clone().into();
local_datetime.format(DATETIME_FORMAT).to_string()
}
/// 定義需要構(gòu)造的協(xié)議
#[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
}
}定義對象的建造者
用于根據(jù)需求創(chuàng)建不同的記錄對象
/// 用于構(gòu)造協(xié)議,通過 Record 和 RecordBuidler 將協(xié)議的讀寫分離
#[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 添加業(yè)務(wù)邏輯
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(())
}
/// 獲得緩存的內(nèi)容
fn bytes(&self) -> &[u8] {
&self.0
}
}
impl Default for Buffer {
fn default() -> Self {
Self::new()
}
}定義用于格式化器的寫緩存
不同的格式化器可以使用不同的緩存,這里使用上面定義的一個簡單的數(shù)組緩存來實(shí)現(xiàn)格式化器需要的緩存。
/// 定義緩存內(nèi)容的格式器
struct FormatterBuffer {
buf: Rc<RefCell<Buffer>>, // RefCell可以修改buf,Rc可以避免使用作用域標(biāo)識
}
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()
}
}定義格式化器
不同的格式化器將記錄轉(zhuǎn)換為不同的格式,寫入到緩存中。
#[derive(Debug)]
/// 格式化器
struct Format<'a> {
buf: &'a mut FormatterBuffer, // 數(shù)據(jù)緩存
sep: &'a str, // 分隔符
}
impl<'a> Format<'a> {
/// 寫數(shù)據(jù)到緩存中
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(), // 操作系統(tǒng)對路徑處理的差異性可能會丟失部分?jǐn)?shù)據(jù)
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(), // 操作系統(tǒng)對路徑處理的差異性可能會panic
self.sep
)
}
None => write!(self.buf, "{}", self.sep),
}
}
}調(diào)用示例
fn main() {
// 創(chuàng)建緩存
let buffer = Rc::new(RefCell::new(Buffer::default()));
let mut format_buffer = FormatterBuffer::new(buffer.clone());
format_buffer.clear();
// 創(chuàng)建一個格式化器
let format = Format { buf: &mut format_buffer, sep: "|" };
// 構(gòu)造事件發(fā)生時間
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();
// 構(gòu)造路徑
let path = Path::new("./foo/bar.txt");
let os_str = OsStr::new("1.png");
// 構(gòu)造記錄
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對象的內(nèi)部值
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
到此這篇關(guān)于rust 一個日志緩存記錄的通用實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)rust日志緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Rust搭建webserver的底層原理與應(yīng)用實(shí)戰(zhàn)技巧
本文介紹Rust在HTTP編程中的應(yīng)用,涵蓋協(xié)議基礎(chǔ)、標(biāo)準(zhǔn)庫與第三方庫(如hyper、reqwest)的使用,以及多線程服務(wù)器和線程池的實(shí)現(xiàn)與關(guān)閉機(jī)制,展示Rust在性能、安全和并發(fā)方面的優(yōu)勢,感興趣的朋友跟隨小編一起看看吧2025-06-06
Rust語言從入門到精通系列之Iterator迭代器深入詳解
這篇文章主要為大家介紹了Rust語言從入門到精通系列之Iterator迭代器深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Rust可迭代類型迭代器正確創(chuàng)建自定義可迭代類型的方法
在 Rust 中, 如果一個類型實(shí)現(xiàn)了 Iterator, 那么它會被同時實(shí)現(xiàn) IntoIterator, 具體邏輯是返回自身, 因?yàn)樽陨砭褪堑?這篇文章主要介紹了Rust可迭代類型迭代器正確創(chuàng)建自定義可迭代類型的方法,需要的朋友可以參考下2023-12-12

