同步异步日志系统-日志落地模块的实现

news2025/2/21 5:12:47

功能:将格式化完成后的日志消息字符串,输出到指定的位置

扩展:支持同时将日志落地到不同的位置

位置分类:

1.标准输出

2.指定文件(时候进行日志分析)

3.滚动文件(文件按照时间/大小进行滚动切换)

扩展:支持落地方向的扩展

        用户可以自己编写一个新的落地模块,将日志进行其他方向的落地。

 实现思想

1.抽象出一个落地基类

2.之后根据落地方向从基类派生出不同落地方向的子类

3.使用工厂模式进行创建与表示分离

标准输出

class StdoutSink :public LogSink{
        public:
            void log(const char* data,size_t len)override{
                std::cout.write(data,len);
            }
    };

输入到指定文件

class FileSink :public LogSink{
        public:
        //传入文件路径,并且打开文件
        FileSink(const std::string& pathname)
        :_pathname(pathname){
            //创建日志文件所在的目录
            util::File::createDirectory(util::File::path(pathname));
            //创建并打开日志文件
            _ofs.open(_pathname,std::ios::binary|std::ios::app);
            assert(_ofs.is_open());//判断文件是否打开
        }
        //将日志消息输入到文件里面
            void log(const char* data,size_t len)override{
                _ofs.write(data,len);
                assert(_ofs.good());
            }
        private:
        std::string _pathname;
        std::ofstream _ofs;
    };

以大小进行滚动

class RollBySizeSink :public LogSink{
        public:
        //传入文件路径,并且打开文件
        RollBySizeSink(const std::string& basename,size_t max_size)
        :_basename(basename),_max_fsize(max_size),_cur_fsize(0){
            std::string pathname = createNewFile();
            //创建日志文件所在的目录
            util::File::createDirectory(util::File::path(pathname));
            //创建并打开日志文件
            _ofs.open(pathname,std::ios::binary|std::ios::app);
            assert(_ofs.is_open());//判断文件是否打开
        }
        //写入前判断文件大小,超过了最大大小就要切换文件
            void log(const char* data,size_t len)override{
                if(_cur_fsize>= _max_fsize){
                    std::string pathname = createNewFile();
                    _ofs.close();//关闭原来已经打开的文件。
                    _ofs.open(pathname,std::ios::binary|std::ios::app);
                    assert(_ofs.is_open());
                    _cur_fsize = 0;
                }
                _ofs.write(data,len);
                assert(_ofs.good());
                _cur_fsize += len;
            }
        private:
            std::string createNewFile(){
                //获取系统时间,以时间来构造文件扩展名
                time_t t = util::Date::now();
                struct tm lt;
                localtime_r(&t,&lt);//将时间戳转换为有年月日的结构
                std::stringstream filename;
                filename << _basename;
                filename << lt.tm_year+1900;
                filename << lt.tm_mon+1;
                filename << lt.tm_mday;
                filename << lt.tm_hour;
                filename << lt.tm_min;
                filename << lt.tm_sec;
                filename << "-";
                filename <<_name_count++;
                filename << ".log";
                return filename.str();
            }//进行大小判断,超过指定大小就要切换新文件
        private:
        //基础文件名+扩展文件名(时间生成)组成一个实际的当前输出文件名
            size_t _name_count=0;
            std::string _basename;
            std::ofstream _ofs;
            size_t _max_fsize;//记录最大大小,当前文件超过了这个大小就要切换文件
            size_t _cur_fsize;//记录当前文件已经写入的大小
    };

以时间进行滚动

enum class TimeGap{
    GAP_SECOND,
    GAP_MIUTE,
    GAP_HOUR,
    GAP_DAY,
};
 class RollByTimeSink :public bitlog::LogSink{
        public:
        //传入文件路径,并且打开文件
        RollByTimeSink(const std::string& basename,TimeGap gap_type)
        :_basename(basename){
            switch(gap_type){
                case TimeGap::GAP_SECOND:_gap_size = 1;break;
                case TimeGap::GAP_MIUTE:_gap_size = 60;break;
                case TimeGap::GAP_HOUR:_gap_size = 3600;break;
                case TimeGap::GAP_DAY:_gap_size = 3600*24;break;
            }
            _cur_gap = _gap_size == 1 ? bitlog::util::Date::now() : bitlog::util::Date::now() % _gap_size;
            std::string filename = createNewFile();
            //创建日志文件所在的目录
            bitlog::util::File::createDirectory(bitlog::util::File::path(filename));
            //创建并打开日志文件
            _ofs.open(filename,std::ios::binary|std::ios::app);
            assert(_ofs.is_open());//判断文件是否打开
        }
        //写入前判断文件大小,超过了最大大小就要切换文件
            void log(const char* data,size_t len)override{
            time_t cur =bitlog::util::Date::now();
                if((cur%_gap_size)!=_cur_gap){
                    _ofs.close();
                    std::string filename = createNewFile();
                    _ofs.open(filename,std::ios::binary|std::ios::app);
                    assert(_ofs.is_open());
                }
                _ofs.write(data,len);
                assert(_ofs.good());
                
            }
        private:
            std::string createNewFile(){
                //获取系统时间,以时间来构造文件扩展名
                time_t t = bitlog::util::Date::now();
                struct tm lt;
                localtime_r(&t,&lt);//将时间戳转换为有年月日的结构
                std::stringstream filename;
                filename << _basename;
                filename << lt.tm_year+1900;
                filename << lt.tm_mon+1;
                filename << lt.tm_mday;
                filename << lt.tm_hour;
                filename << lt.tm_min;
                filename << lt.tm_sec;
                filename << ".log";
                return filename.str();
            }//进行大小判断,超过指定大小就要切换新文件
        private:
        std::string _basename;
        std::ofstream _ofs;
        size_t _cur_gap;//当前是第几个时间段
        size_t _gap_size;//时间段的大小
    };

使用简易工厂模式来创建

class SinkFactory{
        public:
        template<typename SinkType,typename ...Args>
            static LogSink::ptr create(Args &&...args){
                return std::make_shared<SinkType>(std::forward<Args>(args)...);
            }

    };

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2301096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用deepseek学大模型08-长短时记忆网络 (LSTM)

deepseek.com 从入门到精通长短时记忆网络(LSTM),着重介绍的目标函数&#xff0c;损失函数&#xff0c;梯度下降 标量和矩阵形式的数学推导&#xff0c;pytorch真实能跑的代码案例以及模型,数据&#xff0c; 模型应用场景和优缺点&#xff0c;及如何改进解决及改进方法数据推导…

(蓝桥杯——10. 小郑做志愿者)洛斯里克城志愿者问题详解

题目背景 小郑是一名大学生,她决定通过做志愿者来增加自己的综合分。她的任务是帮助游客解决交通困难的问题。洛斯里克城是一个六朝古都,拥有 N 个区域和古老的地铁系统。地铁线路覆盖了树形结构上的某些路径,游客会询问两个区域是否可以通过某条地铁线路直达,以及有多少条…

小胡说技书博客分类(部分目录):服务治理、数据治理与安全治理对比表格

文章目录 一、对比表格二、目录2.1 服务2.2 数据2.3 安全 一、对比表格 下表从多个维度对服务治理、数据治理和安全治理进行详细对比&#xff0c;为读者提供一个直观而全面的参考框架。 维度服务治理数据治理安全治理定义对软件开发全流程、应用交付及API和接口管理进行规范化…

开源模型应用落地-DeepSeek-R1-Distill-Qwen-7B-LoRA微调-LLaMA-Factory-单机单卡-V100(一)

一、前言 如今&#xff0c;大语言模型领域热闹非凡&#xff0c;各种模型不断涌现。DeepSeek-R1-Distill-Qwen-7B 模型凭借其出色的效果和性能&#xff0c;吸引了众多开发者的目光。而 LLaMa-Factory 作为强大的微调工具&#xff0c;能让模型更好地满足个性化需求。 在本篇中&am…

uni-app发起网络请求的三种方式

uni.request(OBJECT) 发起网络请求 具体参数可查看官方文档uni-app data:请求的参数; header&#xff1a;设置请求的 header&#xff0c;header 中不能设置 Referer&#xff1b; method&#xff1a;请求方法&#xff1b; timeout&#xff1a;超时时间&#xff0c;单位 ms&a…

EasyRTC:智能硬件适配,实现多端音视频互动新突破

一、智能硬件全面支持&#xff0c;轻松跨越平台障碍 EasyRTC 采用前沿的智能硬件适配技术&#xff0c;无缝对接 Windows、macOS、Linux、Android、iOS 等主流操作系统&#xff0c;并全面拥抱 WebRTC 标准。这一特性确保了“一次开发&#xff0c;多端运行”的便捷性&#xff0c…

LeetCode1287

LeetCode1287 目录 题目描述示例思路分析代码段代码逐行讲解复杂度分析总结的知识点整合总结 题目描述 给定一个非递减的整数数组 arr&#xff0c;其中有一个元素恰好出现超过数组长度的 25%。请你找到并返回这个元素。 示例 示例 1 输入: arr [1, 2, 2, 6, 6, 6, 6, 7,…

深度学习笔记之自然语言处理(NLP)

深度学习笔记之自然语言处理(NLP) 在行将开学之时&#xff0c;我将开始我的深度学习笔记的自然语言处理部分&#xff0c;这部分内容是在前面基础上开展学习的&#xff0c;且目前我的学习更加倾向于通识。自然语言处理部分将包含《动手学深度学习》这本书的第十四章&#xff0c…

自动化测试框架搭建-单次接口执行-三部曲

目的 判断接口返回值和提前设置的预期是否一致&#xff0c;从而判断本次测试是否通过 代码步骤设计 第一步&#xff1a;前端调用后端已经写好的POST接口&#xff0c;并传递参数 第二步&#xff1a;后端接收到参数&#xff0c;组装并请求指定接口&#xff0c;保存返回 第三…

DeepSeek R1生成图片总结2(虽然本身是不能直接生成图片,但是可以想办法利用别的工具一起实现)

DeepSeek官网 目前阶段&#xff0c;DeepSeek R1是不能直接生成图片的&#xff0c;但可以通过优化文本后转换为SVG或HTML代码&#xff0c;再保存为图片。另外&#xff0c;Janus-Pro是DeepSeek的多模态模型&#xff0c;支持文生图&#xff0c;但需要本地部署或者使用第三方工具。…

ESP32 ESP-IDF TFT-LCD(ST7735 128x160) LVGL基本配置和使用

ESP32 ESP-IDF TFT-LCD(ST7735 128x160) LVGL基本配置和使用 &#x1f4cd;项目地址&#xff1a;https://github.com/lvgl/lv_port_esp32参考文章&#xff1a;https://blog.csdn.net/chentuo2000/article/details/126668088https://blog.csdn.net/p1279030826/article/details/…

【笔记】LLM|Ubuntu22服务器极简本地部署DeepSeek+联网使用方式

2025/02/18说明&#xff1a;2月18日~2月20日是2024年度博客之星投票时间&#xff0c;走过路过可以帮忙点点投票吗&#xff1f;我想要前一百的实体证书&#xff0c;经过我严密的计算只要再拿到60票就稳了。一人可能会有多票&#xff0c;Thanks♪(&#xff65;ω&#xff65;)&am…

Linux的基础指令和环境部署,项目部署实战(下)

目录 上一篇&#xff1a;Linxu的基础指令和环境部署&#xff0c;项目部署实战&#xff08;上&#xff09;-CSDN博客 1. 搭建Java部署环境 1.1 apt apt常用命令 列出所有的软件包 更新软件包数据库 安装软件包 移除软件包 1.2 JDK 1.2.1. 更新 1.2.2. 安装openjdk&am…

数值积分:通过复合梯形法计算

在物理学和工程学中&#xff0c;很多问题都可以通过数值积分来求解&#xff0c;特别是当我们无法得到解析解时。数值积分是通过计算积分区间内离散点的函数值来近似积分的结果。在这篇博客中&#xff0c;我将讨论如何使用 复合梯形法 来进行数值积分&#xff0c;并以一个简单的…

【Java计算机毕业设计】基于SSM+VUE保险公司管理系统数据库源代码+LW文档+开题报告+答辩稿+部署教程+代码讲解

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿 部署教程代码讲解代码时间修改教程 一、开发工具、运行环境、开发技术 开发工具 1、操作系统&#xff1a;Window操作系统 2、开发工具&#xff1a;IntelliJ IDEA或者Eclipse 3、数据库存储&#xff1a…

C#之上位机开发---------C#通信库及WPF的简单实践

〇、上位机&#xff0c;分层架构 界面层 要实现的功能&#xff1a; 展示数据 获取数据 发送数据 数据层 要实现的功能&#xff1a; 转换数据 打包数据 存取数据 通信层 要实现的功能&#xff1a; 打开连接 关闭连接 读取数据 写入数据 实体类 作用&#xff1a; 封装数据…

仿 Sora 之形,借物理模拟之技绘视频之彩

来自麻省理工学院、斯坦福大学、哥伦比亚大学以及康奈尔大学的研究人员携手开源了一款创新的3D交互视频模型——PhysDreamer&#xff08;以下简称“PD”&#xff09;。PD与OpenAI旗下的Sora相似&#xff0c;能够借助物理模拟技术来生成视频&#xff0c;这意味着PD所生成的视频蕴…

RedisTemplate存储含有特殊字符解决

ERROR信息: 案发时间: 2025-02-18 01:01 案发现场: UserServiceImpl.java 嫌疑人: stringRedisTemplate.opsForValue().set(SystemConstants.LOGIN_CODE_PREFIX phone, code, Duration.ofMinutes(3L)); // 3分钟过期作案动机: stringRedisTemplate继承了Redistemplate 使用的…

Django REST Framework (DRF) 中用于构建 API 视图类解析

Django REST Framework (DRF) 提供了丰富的视图类&#xff0c;用于构建 API 视图。这些视图类可以分为以下几类&#xff1a; 1. 基础视图类 这些是 DRF 中最基础的视图类&#xff0c;通常用于实现自定义逻辑。 常用类 APIView&#xff1a; 最基本的视图类&#xff0c;所有其…

Zotero PDF Translate插件配置百度翻译api

Zotero PDF Translate插件可以使用几种翻译api&#xff0c;虽然谷歌最好用&#xff0c;但是由于众所周知的原因&#xff0c;不稳定。而cnki有字数限制&#xff0c;有道有时也不行。其他的翻译需要申请密钥。本文以百度为例&#xff0c;进行申请 官方有申请教程&#xff1a; Zot…