• 【C++模块实现】| 【06】日志模块添加循环覆盖写文件功能


    ========》以下全部代码查看《========

    索引

    【C++模块实现】| 【01】日志系统实现
    【C++模块实现】| 【02】日志系统优化
    【C++模块实现】| 【03】文件管理模块
    【C++模块实现】| 【04】配置模块
    【C++模块实现】| 【05】日志模块增加配置模块的功能

    1、简介

    结合前面的配置模块,我们已经将日志系统的配置项通过配置模块进行加载;
    但该日志系统中没有提供循环覆盖写文件功能,故本节将参考网上一些文章对其进行完善;
    
    • 1
    • 2
    结合参考的文章,做出了一些简单的循环覆盖写文件:
    首先配置中设定日志保存的期限、日志文件的内存上限以及扩张的文件数(log1.txt、log2.txt),可以有多种方式,可以按时间进行文
    件划分,但本次只简单的设置按个数划分;
    方法一:通过检查文件每个文件的日期,若文件数没有到达限制个数,则创建它做为日志副本;
    		否则直接将文件修改日志最小的(即最早生成的)作为日志的存储副本;
    【如:】若限定最多生成5个文件数(log1.txt、log2.txt、log3.txt、log4.txt、log5.txt),日志只往log.txt中写入,
    	当log.txt写满时,将遍历这5个文件,若文件不存在,则直接移动到该文件,若存在,则移动到文件修改日期最早的那个文件;
    
    方法二:
    	在配置中增添一项用来记录日志更新到第几个文件数file_num;
    	当log.txt文件写满时,先检查各个文件日志是否存在,若存在则检查是否过期,若过期则删除,且log.txt日志直接移动到
    	该日志文件中,若不存在,则log.txt直接移动到该日志文件中,若满足期限且存在,则移动到logfile_num.txt中;
    	该file_num若有变动,则会对配置文件进行更新记录,便于下次加载;
    
    上述方法测试,暂时没有问题,只是简单的实现,若有其他缺漏,或方法不适用,麻烦各位指点。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2、遇到的问题

    2.1 日志文件大小的限制没有达到预期的要求
    在这里插入图片描述

    每次进入该判断时,文件大小是正确的,但后续对文件进行移动的时候却显示文件的大小远大于该限制;
    后面发现没有对该文件进行关闭操作,应该是缓冲区中的内容还没有写入到文件中导致的;
    后续在此处对文件关闭即解决
    
    • 1
    • 2
    • 3

    2.2 yamlstring

    当配置项的内容有更新时,需要回写到配置文件时,将YAML::Node格式的内容压入stringstream中后写入文件格式出现问题;
    后续提供toYaml接口,和toYamlString分开;
    以下是错误格式:
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    3、代码改进

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    struct stat st;
    /* 判断文件是否满了 */
    if(!stat(m_filename.c_str(), &st)) {
    if(st.st_size > m_file_buf) {    // 判断文件是否写满了
        m_filestream.close();	
        std::string newFile = m_filename.substr(0, m_filename.rfind('.'));
        int i;
    //            /**方法一: 查看日志文件的修改文件的时间,哪个最旧,即替换哪个 */
    //            /*uint64_t t = INT64_MAX;
    //            int idx=0;
    //            for(i=1; i<=backups_files ; ++i) {
    //                std::string tmp = newFile + std::to_string(i) + ".txt";
    //                if(!stat(tmp.c_str(), &st)) {
    //                    idx = i;
    //                    break;
    //                }
    //
    //                if(((time(0) - st.st_mtime) / 24 * 60 * 60) > backups_days) {
    //                    FSUtil::Rm(tmp);
    //                    idx = i;
    //                    break;
    //                }
    //                if(t >= st.st_mtime){
    //                    t = st.st_mtime;
    //                    idx=i;
    //                    newFile = tmp;
    //                }
    //            }
    //            FSUtil::Mv(m_filename, newFile);
    //            FSUtil::Rm(m_filename);
    //    		  FSUtil::OpenForWrite(m_filestream, m_filename.c_str(), std::ios::app);
    //            */
    //
        /** 方法二:根据记录 */
        for(i=1; i<=m_backups_files ; ++i) {
            std::string tmp = newFile + std::to_string(i) + ".txt";
            if(stat(tmp.c_str(), &st)) {   // 判断文件是否存在
                break;
            }
            /* 判断日志是否过期 */
            if(((time(0) - st.st_mtime) / (24 * 60 * 60)) > m_backups_days) {
                FSUtil::Rm(tmp);
            }
        }
        FSUtil::Mv(m_filename, newFile+std::to_string(m_file_num) + ".txt");
        FSUtil::Rm(m_filename);
    
        FSUtil::OpenForWrite(m_filestream, m_filename.c_str(), std::ios::app);
        m_file_num += 1;
        if(m_file_num > m_backups_files) m_file_num = 1;
        IsChange = true;	// 若为true则需要更新yaml配置文件
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    4、测试

    测试循环覆盖写文件

    此时的配置文件为:
    
    • 1

    在这里插入图片描述

    测试代码

    #include 
    #include "../sylar/log.h"
    #include "../sylar/util.h"
    #include "../sylar/config.h"
    #include 
    
    #include 
    
    int main(int argc, char** argv) {
    
        sylar::Logger::ptr g_logger = SYLAR_LOG_NAME("root");
    
        sylar::Config::LoadFromYaml("/root/code/log_server/bin/conf/log.yml");
        // 输出日志
        std::cout << g_logger->toYamlString() << std::endl;
        for(int i=0; i<160000; ++i) {
            SYLAR_LOG_INFO(g_logger) << i;
            sleep(1);
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述
    在这里插入图片描述

    参考文章

    =========》Log4j2 RollingFileAppender《=========
    =========》滚动文件附加器指南《=========
    =========》RollingFileWithCleanupAppender《=========

  • 相关阅读:
    1017 Queueing at Bank
    Linux线程池
    代码随想录算法训练营day6| 哈希表理论基础、242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和
    Docker、Jenkins 结合 SonarQube 和 Sonar scanner 进行代码质量扫描
    2021上海市赛【10.10训练补题】
    WSO2 API Manager代码问题漏洞(CVE-2022-29464)
    聊聊Http服务化改造实践
    Java --- IO流
    MySQL 安全相关配置参数
    【面试高高手】 —— Java集合篇(23题)
  • 原文地址:https://blog.csdn.net/weixin_45926547/article/details/126055943