建网站大公司/太原seo快速排名
本文给出了一个通用的设计模式,通过建造者模式实例化记录对象,可自定义格式化器将实例化后的记录对象写入到指定的缓存对象中。
定义记录对象
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(), // 操作系统对路径处理的差异性可能会panicself.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 - 一个日志缓存记录的通用实现
本文给出了一个通用的设计模式,通过建造者模式实例化记录对象,可自定义格式化器将实例化后的记录对象写入到指定的缓存对象中。 定义记录对象 use chrono::prelude::*; use std::{cell::RefCell, ffi::OsStr, fmt, io, io::Write, path::Path, rc::Rc,…...

elasticsearch(RestHighLevelClient API操作)(黑马)
操作全是换汤不换药,创建一个request,然后使用client发送就可以了 一、增加索引库数据 Testvoid testAddDocument() throws IOException {//从数据库查出数据Writer writer writerService.getById(199);//将查出来的数据处理成json字符串String json …...

用尾插的思想实现移除链表中的元素
目录 一、介绍尾插 1.链表为空 2.链表不为空 二、题目介绍 三、思路 四、代码 五、代码解析 1. 2. 3. 4. 5. 6. 六、注意点 1. 2. 一、介绍尾插 整体思路为 1.链表为空 void SLPushBack(SLTNode** pphead, SLTDataType x) {SLTNode* newnode BuyLTNode(x); …...

【Kubernetes】k8s删除master节点后重新加入集群
目录 前言一、思路二、实战1.安装etcdctl指令2.重置旧节点的k8s3.旧节点的的 etcd 从 etcd 集群删除4.在 master03 上,创建存放证书目录5.把其他控制节点的证书拷贝到 master01 上6.把 master03 加入到集群7.验证 master03 是否加入到 k8s 集群,检查业务…...

HCIP—OSPF虚链路实验
OSPF虚链路—Vlink 作用:专门解决OSPF不规则区域所诞生的技术,是一种虚拟的,逻辑的链路。实现非骨干区域和骨干区域在逻辑上直接连接。注意虚链路条件:只能穿越一个区域,通常对虚链路进行认证功能的配置。虚链路认证也…...

RAxML-NG安装与使用-raxml-ng-v1.2.0(bioinfomatics tools-013)
01 背景 1.1 ML树 ML树,或最大似然树,是一种在进化生物学中用来推断物种之间进化关系的方法。最大似然(Maximum Likelihood, ML)是一种统计框架,用于估计模型参数,使得观察到的数据在该模型参数下的概率最…...

Tomcat内存马
Tomcat内存马 前言 描述Servlet3.0后允许动态注册组件 这一技术的实现有赖于官方对Servlet3.0的升级,Servlet在3.0版本之后能够支持动态注册组件。 而Tomcat直到7.x才支持Servlet3.0,因此通过动态添加恶意组件注入内存马的方式适合Tomcat7.x及以上。…...

pytorch之诗词生成3--utils
先上代码: import numpy as np import settingsdef generate_random_poetry(tokenizer, model, s):"""随机生成一首诗:param tokenizer: 分词器:param model: 用于生成古诗的模型:param s: 用于生成古诗的起始字符串,默认为空串:return: …...

OpenAI的ChatGPT企业版专注于安全性、可扩展性和定制化。
OpenAI的ChatGPT企业版:安全、可扩展性和定制化的重点 OpenAI的ChatGPT在商业世界引起了巨大反响,而最近推出的ChatGPT企业版更是证明了其在企业界的日益重要地位。企业版ChatGPT拥有企业级安全、无限GPT-4访问、更长的上下文窗口以及一系列定制选项等增…...

JS06-class对象
class对象 className 修改样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&quo…...

深度学习1650ti在win10安装pytorch复盘
深度学习1650ti在win10安装pytorch复盘 前言1. 安装anaconda2. 检查更新显卡驱动3. 根据pytorch选择CUDA版本4. 安装CUDA5. 安装cuDNN6. conda安装pytorch结语 前言 建议有条件的,可以在安装过程中,开启梯子。例如cuDNN安装时登录 or 注册,会…...

Node.js与webpack(三)
上一节:Node.js与Webpack笔记(二)-CSDN博客 从0来一遍(webpack项目) 将之前的webpack 的纯开发配置,重新创建空白项目,重新做一遍,捋一遍思路防止加入生产模式时候弄混 1.创建文件夹…...

测试覆盖率那些事
在测试过程中,会出现测试覆盖不全的情况,特别是工期紧张的情况下,测试的时间被项目的周期一压再压,测试覆盖概率不全就会伴随而来。 网上冲浪,了解一下覆盖率的文章,其中一篇感觉写的很不错,将…...

Etcd 介绍与使用(入门篇)
etcd 介绍 etcd 简介 etc (基于 Go 语言实现)在 Linux 系统中是配置文件目录名;etcd 就是配置服务; etcd 诞生于 CoreOS 公司,最初用于解决集群管理系统中 os 升级时的分布式并发控制、配置文件的存储与分发等问题。基…...

Docker 安装 LogStash
关于LogStash Logstash,作为Elastic Stack家族中的核心成员之一,是一个功能强大的开源数据收集引擎。它专长于从各种来源动态地获取、解析、转换和丰富数据,并将这些结构化或非结构化的数据高效地传输到诸如Elasticsearch等存储系统中进行集…...

Selenium笔记
Selenium笔记 Selenium笔记 Selenium笔记element not interactable页面刷新 element not interactable "element not interactable"是Selenium在执行与网页元素交互操作(如点击、输入等)时抛出的一个常见错误。这个错误意味着虽然找到了对应的…...

ChatGPT :确定性AI源自于确定性数据
ChatGPT 幻觉 大模型实际应用落地过程中,会遇到幻觉(Hallucination)问题。对于语言模型而言,当生成的文本语法正确流畅,但不遵循原文(Faithfulness),或不符合事实(Factua…...

linux驱动开发面试题
1.linux中内核空间及用户空间的区别? 记住“22”,两级分段两级权限。 例如是32位的机器,从内存空间看:顶层1G是内核的,底3G是应用的;从权限看:内核是0级特权,应用是3级特权。 2.用…...

【AI】Ubuntu系统深度学习框架的神经网络图绘制
一、Graphviz 在Ubuntu上安装Graphviz,可以使用命令行工具apt进行安装。 安装Graphviz的步骤相对简单。打开终端,输入以下命令更新软件包列表:sudo apt update。之后,使用命令sudo apt install graphviz来安装Graphviz软件包。为…...

AI推介-大语言模型LLMs论文速览(arXiv方向):2024.03.05-2024.03.10—(2)
论文目录~ 1.Debiasing Large Visual Language Models2.Harnessing Multi-Role Capabilities of Large Language Models for Open-Domain Question Answering3.Towards a Psychology of Machines: Large Language Models Predict Human Memory4.Can we obtain significant succ…...

AI解答——DNS、DHCP、SNMP、TFTP、IKE、RIP协议
使用豆包帮助我解答计算机网络通讯问题—— 1、DHCP 服务器是什么? DHCP 服务器可是网络世界中的“慷慨房东”哦🤣 它的全称是 Dynamic Host Configuration Protocol(动态主机配置协议)服务器。 DHCP 服务器的主要任务是为网络中的…...

【TypeScript系列】声明合并
声明合并 介绍 TypeScript中有些独特的概念可以在类型层面上描述JavaScript对象的模型。 这其中尤其独特的一个例子是“声明合并”的概念。 理解了这个概念,将有助于操作现有的JavaScript代码。 同时,也会有助于理解更多高级抽象的概念。 对本文件来讲,“声明合并”是指编…...

zookeeper基础学习之六: zookeeper java客户端curator
简介 Curator是Netflix公司开源的一套zookeeper客户端框架,解决了很多Zookeeper客户端非常底层的细节开发工作,包括连接重连、反复注册Watcher和NodeExistsException异常等等。Patrixck Hunt(Zookeeper)以一句“Guava is to Java…...

MySQL数据库操作学习(2)表查询
文章目录 一、表查询1.表字段的操作①查看表结构②字段的增加③字段长度/数据类型的修改④字段名的修改⑤删除字符段⑥清空表数据⑦修改表名⑧删除表 2、表数据查询3、where 字段4、聚合函数 一、表查询 1.表字段的操作 ①查看表结构 desc 表名; # 查看表中的字段类型&#…...

Java学习
目录 treeSet StringBuilder treeSet TreeSet 是 Java 中实现了 Set 接口的一种集合类,它使用红黑树数据结构来存储元素,放到TreeSet集合中的元素: 无序不可重复,但是可以按照元素的大小顺序自动排序。 TreeSet一般会和Iterator迭代器一起使…...

C#八皇后算法:回溯法 vs 列优先法 vs 行优先法 vs 对角线优先法
目录 1.八皇后算法(Eight Queens Puzzle) 2.常见的八皇后算法解决方案 (1)列优先法(Column-First Method): (2)行优先法(Row-First Method)&a…...

springboot整合swagger,postman,接口规范
一、postman介绍 1.1概述 工具下载 Postman(发送 http 请求的工具) 官网(下载速度比较慢):Download Postman | Get Started for Free 网盘下载:百度网盘 请输入提取码 1.2Http 请求格式 请求地址请求方法状…...

029—pandas 遍历行非向量化修改数据
前言 在 pandas 中,向量化计算是指利用 pandas 对象的内置方法和函数,将操作应用到整个数据结构的每个元素,从而在单个操作中完成大量的计算。 但在一些需求中,我们无法使用向量化计算,就需要迭代操作,本例…...

相机安装位置固定后开始调试设备供电公司推荐使用方法
摄像头安装位置固定后开始调试 设备供电:无电源设备需要连接12V/2A电源并连接到摄像机的DC端口,而有电源的摄像机可以直接连接到220V电源。 连接设备:如果是有线连接,请使用网线将设备连接到电脑(建议直接连接&#…...

AI视频批量混剪系统|罐头鱼AI视频矩阵获客
AI视频批量混剪系统助您轻松管理和编辑视频素材 如今,视频营销已成为企业推广的重要方式。为了满足用户对视频管理、发布和编辑的需求,《罐头鱼AI视频批量混剪系统》应运而生。这款智能化系统集成了多种功能,助您轻松管理和发布精彩视频内容…...