rust 一個日志緩存記錄的通用實現(xiàn)方法
本文給出了一個通用的設(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ù)組緩存來實現(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 一個日志緩存記錄的通用實現(xiàn)的文章就介紹到這了,更多相關(guān)rust日志緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
rust?創(chuàng)建多線程web?server的詳細過程
web?server?中主要的兩個協(xié)議是?http?和?tcp,tcp?是底層協(xié)議,http?是構(gòu)建在?tcp?之上的,本篇文章重點給大家介紹rust?創(chuàng)建多線程web?server的詳細過程,感興趣的朋友跟隨小編一起看看吧2023-11-11
rust多個mod文件引用和文件夾mod使用注意事項小結(jié)
在 Rust 項目中,可以使用 mod 關(guān)鍵字將一個文件夾或一個 rs 文件作為一個模塊引入到當(dāng)前文件中,本文給大家介紹rust多個mod文件引用和文件夾mod使用注意事項小結(jié),感興趣的朋友跟隨小編一起看看吧2024-03-03
Rust中使用Serde對json數(shù)據(jù)進行反序列化
JSON作為目前流行的數(shù)據(jù)格式之一,被大家廣泛使用,在日常的開發(fā)實踐中,將JSON數(shù)據(jù)反序列化為對應(yīng)的類型具有重要的意義,在Rust中,Serde幾乎成了JSON數(shù)據(jù)解析的事實標(biāo)準(zhǔn),本文將給大家介紹Rust中使用Serde對json數(shù)據(jù)進行反序列化,需要的朋友可以參考下2024-01-01
libbpf和Rust開發(fā)ebpf程序?qū)崙?zhàn)示例
這篇文章主要為大家介紹了libbpf和Rust開發(fā)ebpf程序?qū)崙?zhàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
Rust語言之Prometheus系統(tǒng)監(jiān)控工具包的使用詳解
Prometheus?是一個開源的系統(tǒng)監(jiān)控和警報工具包,最初是由SoundCloud構(gòu)建的,隨著時間的發(fā)展,Prometheus已經(jīng)具有適用于各種使用場景的版本,為了開發(fā)者方便開發(fā),更是有各種語言版本的Prometheus的開發(fā)工具包,本文主要介紹Rust版本的Prometheus開發(fā)工具包2023-10-10

