Qt 日志文件的滚动写入

news2024/11/18 11:57:24

Qt 日志文件的滚动写入

flyfish

日志文件的滚动写入功能。在日志文件达到10MB时创建新的日志文件,并且在总日志文件大小达到10GB时开始覆盖最早的日志文件

以监控一个文件夹的写日志为例

日志文件创建与管理

初始化日志文件:在FileMonitor类的构造函数中,会创建第一个日志文件。日志文件的命名格式为 “file_monitor_序号.log”,初始序号为 0。

滚动写入机制:

单个日志文件大小限制:当向当前日志文件写入内容使得其大小达到 10MB(通过logFileSizeLimit变量设定,值为10 * 1024 * 1024字节)时,会关闭当前日志文件,增加日志文件索引,然后创建新的日志文件用于后续的日志记录。

总日志文件大小限制:

同时,会监控所有日志文件的总体大小,当总大小达到 10GB(通过totalLogSizeLimit变量设定,值为10 * 1024 * 1024 * 1024字节)时,会删除最早创建的日志文件(通过计算最早日志文件的文件名并判断其是否存在,若存在则删除),以确保总日志文件大小不会无限制增长。

日志内容记录:

对于文件创建、删除、修改等事件,会将事件发生的当前日期时间(格式为 “yyyy-MM-dd hh:mm:ss”)、事件类型(如 “File created”、“File deleted”、“File modified”)以及相关文件的路径信息,按照特定格式写入到当前正在使用的日志文件中。并且每次写入后会立即刷新缓冲区,确保日志内容及时写入文件。同时,会实时更新当前日志文件的大小信息,以便判断是否达到单个日志文件大小限制。


#include <QCoreApplication>
#include <QFileSystemWatcher>
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QDir>
#include <QFileInfo>
#include <QSet>
#include <iostream>

// FileMonitor类继承自QObject,用于监控指定文件夹的文件变化并记录相关日志
class FileMonitor : public QObject {
    Q_OBJECT

public:
    // 构造函数,用于初始化文件监控器相关参数
    explicit FileMonitor(const QString &path, QObject *parent = nullptr)
        : QObject(parent),
          // 创建文件系统监控器对象,并将其作为当前对象的子对象
          watcher(new QFileSystemWatcher(this)),
          rootPath(path),
          // 设置单个日志文件的大小限制为10MB,这里将10MB转换为字节数
          logFileSizeLimit(static_cast<quint64>(10) * 1024 * 1024),
          // 设置总日志文件大小限制为10GB,同样转换为字节数
          totalLogSizeLimit(static_cast<quint64>(10) * 1024 * 1024 * 1024),
          currentLogFileIndex(0),
          currentLogFileSize(0) {

        // 将指定的监控路径添加到文件系统监控器中
        watcher->addPath(rootPath);

        // 获取监控路径下初始的文件列表
        QDir dir(rootPath);
        initialFiles = dir.entryList(QDir::Files);

        // 连接文件系统监控器的目录变化信号到对应的槽函数
        connect(watcher, &QFileSystemWatcher::directoryChanged, this, &FileMonitor::onDirectoryChanged);
        // 连接文件系统监控器的文件变化信号到对应的槽函数
        connect(watcher, &QFileSystemWatcher::fileChanged, this, &FileMonitor::onFileChanged);

        // 初始化日志文件,创建第一个日志文件
        createNewLogFile();
    }

private slots:
    // 当监控的目录发生变化时调用的槽函数
    void onDirectoryChanged(const QString &path) {
        std::cout << "Directory changed: " << qPrintable(path) << std::endl;

        // 获取当前监控目录下的文件列表
        QDir dir(rootPath);
        QStringList currentFiles = dir.entryList(QDir::Files);

        // 找出新增的文件,通过集合运算实现
        QSet<QString> newFiles = QSet<QString>(currentFiles.begin(), currentFiles.end()).subtract(QSet<QString>(initialFiles.begin(), initialFiles.end()));
        // 遍历新增的文件,记录文件创建事件到日志
        for (const QString &file : newFiles) {
            logEvent("File created", dir.absoluteFilePath(file));
        }

        // 找出被删除的文件,同样通过集合运算
        QSet<QString> deletedFiles = QSet<QString>(initialFiles.begin(), initialFiles.end()).subtract(QSet<QString>(currentFiles.begin(), currentFiles.end()));
        // 遍历被删除的文件,记录文件删除事件到日志
        for (const QString &file : deletedFiles) {
            logEvent("File deleted", dir.absoluteFilePath(file));
        }

        // 更新初始文件列表,使其为当前的文件列表,以便下次检测文件变化
        initialFiles = currentFiles;
    }

    // 当监控的文件发生变化时调用的槽函数
    void onFileChanged(const QString &path) {
        std::cout << "File changed: " << qPrintable(path) << std::endl;
        // 记录文件修改事件到日志
        logEvent("File modified", path);
    }

private:
    // 创建新的日志文件的函数
    void createNewLogFile() {
        // 构造新的日志文件名,格式为:file_monitor_序号.log
        QString logFileName = "file_monitor_" + QString::number(currentLogFileIndex) + ".log";
        currentLogFile.setFileName(logFileName);

        // 如果日志文件已经存在,获取其大小并更新当前日志文件大小变量
        if (currentLogFile.exists()) {
            currentLogFileSize = currentLogFile.size();
        } else {
            currentLogFileSize = 0;
        }

        // 打开或创建日志文件,如果失败则输出错误信息
        if (!currentLogFile.open(QIODevice::Append | QIODevice::Text)) {
            std::cerr << "Failed to open/create log file: " << qPrintable(logFileName) << std::endl;
        }
    }

    // 记录日志事件的函数
    void logEvent(const QString &event, const QString &path) {
        // 创建文本流对象,用于向当前日志文件写入内容
        QTextStream out(&currentLogFile);
        // 写入当前日期时间、事件类型和文件路径信息到日志文件
        out << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
            << " - " << event << ": " << path << "\n";
        currentLogFile.flush();

        // 计算刚写入的日志字符串的大小,先读取文本流中的内容
        QString logString = out.readAll();
        // 如果读取为空,说明可能是因为刚刚写入还未缓存,重新构造日志字符串
        if (logString.isEmpty()) {
            logString = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")
                        + " - " + event + ": " + path + "\n";
        }

        // 更新当前日志文件的大小,将日志字符串转换为UTF-8编码后计算其字节数并累加到当前日志文件大小变量
        currentLogFileSize += logString.toUtf8().size();

        // 检查当前日志文件大小是否达到单个日志文件大小限制
        if (currentLogFileSize >= logFileSizeLimit) {
            // 关闭当前日志文件
            currentLogFile.close();

            // 增加日志文件索引,用于创建下一个新的日志文件
            ++currentLogFileIndex;

            // 检查是否超过了总日志文件大小限制,如果超过则删除最早的日志文件
            if (currentLogFileIndex * logFileSizeLimit > totalLogSizeLimit) {
                QString oldestLogFileName = "file_monitor_" + QString::number(currentLogFileIndex - totalLogSizeLimit / logFileSizeLimit) + ".doc";
                if (QFile::exists(oldestLogFileName)) {
                    QFile::remove(oldestLogFileName);
                }
            }

            // 创建新的日志文件
            createNewLogFile();
        }
    }

    // 文件系统监控器对象,用于监控指定路径下的文件和目录变化
    QFileSystemWatcher *watcher;
    // 监控的根路径
    QString rootPath;
    // 初始的文件列表,用于对比检测文件的新增和删除情况
    QStringList initialFiles;

    // 以下是新增的日志管理相关成员变量

    // 当前正在使用的日志文件对象
    QFile currentLogFile;
    // 单个日志文件的大小限制,单位为字节
    quint64 logFileSizeLimit;
    // 总日志文件大小限制,单位为字节
    quint64 totalLogSizeLimit;
    // 当前日志文件的索引,用于区分不同的日志文件
    quint64 currentLogFileIndex;
    // 当前日志文件的大小,单位为字节,用于实时监控文件大小是否达到限制
    quint64 currentLogFileSize;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 获取命令行参数,如果有参数则将其作为监控路径,否则默认监控根目录
    QString watchPath = (argc > 1)? QString::fromLocal8Bit(argv[1]) : "/";

    // 创建文件监控对象,传入监控路径
    FileMonitor monitor(watchPath);

    // 运行应用程序的事件循环,开始监控文件和目录变化并记录日志
    return a.exec();
}

#include "main.moc"

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

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

相关文章

快速搭建Android开发环境:Docker部署docker-android并实现远程连接

目录 前言 1. 虚拟化环境检查 2. Android 模拟器部署 3. Ubuntu安装Cpolar 4. 配置公网地址 5. 远程访问 小结 6. 固定Cpolar公网地址 7. 固定地址访问 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊快速搭建Android开发环境&#x…

大麦抢票科技

仅供学习参考&#xff0c;切勿再令您所爱的人耗费高昂的价格去购置黄牛票 ⚠️核心内容参考: 据悉&#xff0c;于购票环节&#xff0c;大麦凭借恶意流量清洗技术&#xff0c;于网络层实时甄别并阻拦凭借自动化手段发起下单请求的流量&#xff0c;强化对刷票脚本、刷票软件以及…

【STM32】基于SPI协议读写SD,详解!

文章目录 0 前言1 SD卡的种类和简介1.1 SD卡的种类1.2 SD卡的整体结构1.3 SD卡运行机制——指令和响应2 SD卡的通信总线2.1 SDIO2.2 SPI3 硬件连接4 代码实践【重点】4.1 HAL库移植4.2 标准库移植4.3 遇到的问题和解决方案5 扩展阅读0 前言 因为项目需要,使用stm32读写sd卡,这…

kafka管理工具

文章目录 前言一、Kafka Assistan1.1 描述1.2、配置安装 二、Conduktor2.1、描述2.2、配置安装 三、kafka-maneger3.1、描述3.2、配置安装3.3、命令启动3.4、[refer to](https://www.ctyun.cn/document/10000120/10033218#section-39755766f4910e4b) 前言 提示&#xff1a;这里…

leetcode_二叉树最大深度

对二叉树的理解 对递归调用的理解 对内存分配的理解 基础数据结构&#xff08;C版本&#xff09; - 飞书云文档 每次函数的调用 都会进行一次新的栈内存分配 所以lmax和rmax的值不会混在一起 /*** Definition for a binary tree node.* struct TreeNode {* int val;* …

使用 Axios 拦截器优化 HTTP 请求与响应的实践

目录 前言1. Axios 简介与拦截器概念1.1 Axios 的特点1.2 什么是拦截器 2. 请求拦截器的应用与实践2.1 请求拦截器的作用2.2 请求拦截器实现 3. 响应拦截器的应用与实践3.1 响应拦截器的作用3.2 响应拦截器实现 4. 综合实例&#xff1a;一个完整的 Axios 配置5. 使用拦截器的好…

高亚科技签约美妥维志化工,提升业务协同与项目运营效率

近日&#xff0c;中国企业管理软件资深服务商高亚科技与韶关美妥维志化工有限公司&#xff08;以下简称“美妥维志”&#xff09;正式签约。基于高亚科技的8Manage PM项目管理软件&#xff0c;美妥维志将实现项目进度、人员审批及问题的统一管理&#xff0c;提升部门间协同效率…

使用真实 Elasticsearch 进行更快的集成测试

作者&#xff1a;来自 Elastic Piotr Przybyl 了解如何使用各种数据初始化和性能改进技术加快 Elasticsearch 的自动化集成测试速度。 在本系列的第 1 部分中&#xff0c;我们探讨了如何编写集成测试&#xff0c;让我们能够在真实的 Elasticsearch 环境中测试软件&#xff0c;并…

数据分布之指数分布(sample database classicmodels _No.10)

数据分布之指数分布&#xff08;sample database classicmodels _No.10&#xff09; 准备工作&#xff0c;可以去下载 classicmodels 数据库具体如下 点击&#xff1a;classicmodels 也可以去 下面我的博客资源下载 https://download.csdn.net/download/tomxjc/88685970 文章…

RPC-健康检测机制

什么是健康检测&#xff1f; 在真实环境中服务提供方是以一个集群的方式提供服务&#xff0c;这对于服务调用方来说&#xff0c;就是一个接口会有多个服务提供方同时提供服务&#xff0c;调用方在每次发起请求的时候都可以拿到一个可用的连接。 健康检测&#xff0c;能帮助从连…

Flink_DataStreamAPI_执行环境

DataStreamAPI_执行环境 1创建执行环境1.1getExecutionEnvironment1.2createLocalEnvironment1.3createRemoteEnvironment 2执行模式&#xff08;Execution Mode&#xff09;3触发程序执行 Flink程序可以在各种上下文环境中运行&#xff1a;我们可以在本地JVM中执行程序&#x…

Cyberchef配合Wireshark提取并解析HTTP/TLS流量数据包中的文件

本文将介绍一种手动的轻量级的方式&#xff0c;还原HTTP/TLS协议中传输的文件&#xff0c;为流量数据包中的文件分析提供帮助。 如果捕获的数据包中存在非文本类文件&#xff0c;例如png,jpg等图片文件&#xff0c;或者word&#xff0c;Excel等office文件异或是其他类型的二进…

Golang云原生项目:—实现ping操作

熟悉报文结构 ICMP校验和算法&#xff1a; 报文内容&#xff0c;相邻两个字节拼接到一起组成一个16bit数&#xff0c;将这些数累加求和若长度为奇数&#xff0c;则将剩余一个字节&#xff0c;也累加求和得出总和之后&#xff0c;将和值的高16位与低16位不断求和&#xff0c;直…

基于STM32 HAL库的FFT计算与数学运算:幅值、频率、均方根、平均值、最大值、最小值、峰峰值与标准差

一、用STM32进行FFT计算与数学运算的过程 1. 信号采集 首先&#xff0c;我们需要使用STM32的ADC模块来采集模拟信号&#xff0c;比如三相交流电。ADC将模拟信号&#xff08;如电压或电流&#xff09;转换为数字信号&#xff0c;供后续处理。 采样数量&#xff1a;FFT的计算通…

关于Github报错Verify your two-factor authentication (2FA) settings的解决方案

如果我们在使用GitHub出现2FA验证问题&#xff1a;Verify your two-factor authentication (2FA) settings&#xff0c;那么可以参考下面的解决方法解决问题。 当然&#xff0c;如果有国外的手机号直接使用验证码接收就可以&#xff0c;问题是不支持中国手机啊。那么怎么办呢&…

【机器学习chp2】贝叶斯最优分类器、概率密度函数的参数估计、朴素贝叶斯分类器、高斯判别分析。万字超详细分析总结与思考

前言&#xff0c;请先看。 本文的《一》《二》属于两个单独的知识点&#xff1a;共轭先验和Laplace平滑&#xff0c;主要因为他们在本文的后续部分经常使用&#xff0c;又因为他们是本人的知识盲点&#xff0c;所以先对这两个知识进行了分析&#xff0c;后续内容按照标题中的顺…

游戏引擎学习第16天

视频参考:https://www.bilibili.com/video/BV1mEUCY8EiC/ 这些字幕讨论了编译器警告的概念以及如何在编译过程中启用和处理警告。以下是字幕的内容摘要&#xff1a; 警告的定义&#xff1a;警告是编译器用来告诉你某些地方可能存在问题&#xff0c;尽管编译器不强制要求你修复…

01.防火墙概述

防火墙概述 防火墙概述1. 防火墙的分类2. Linux 防火墙的基本认识3. netfilter 中五个勾子函数和报文流向 防火墙概述 防火墙&#xff08; FireWall &#xff09;&#xff1a;隔离功能&#xff0c;工作在网络或主机边缘&#xff0c;对进出网络或主机的数据包基于一定的 规则检…

express 从0-1如何创建一个项目 注册接口

内容参考&#xff1a; windos下安装mysql express 使用mysql 一、创建一个空项目 二、创建一个包管理工具 npm init -y三、安装需要的插件及app.js的部分实现 npm i express 安装express 框架 npm i cors 安装cors 用于跨域 npm install mysql2 安装mysql数据库 npm i b…

Shell基础(4)

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团…