使用C++和QT实现Log自定义日志系统

这篇具有很好参考价值的文章主要介绍了使用C++和QT实现Log自定义日志系统。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

MyLog

说明

使用C++和QT实现Log自定义日志系统

  • 使用QT的qInstallMessageHandler函数结合qDebug,qInfo实现自定义的日志系统
  • 输出日志到文件和控制台
  • 自动检测日志文件大小
  • 自动更新日志文件修改日期
  • 自动备份
  • 自动删除一个月前的日志文件
  • 支持多线程程序
  • 支持扩展,可输出日志到数据库,网络,或服务器
  • 支持扩展,可使用config文件进行配置

警告

  • 注:博主所有资源永久免费,若有帮助,请点赞转发是对我莫大的帮助
  • 注:博主本人学习过程的分享,引用他人的文章皆会标注原作者
  • 注:本人文章非盈利性质,若有侵权请联系我删除
  • 注:获取资源或者咨询问题请联系Q:2950319782
  • 注:博主本人很菜,文章基本是二次创作,大佬请忽略我的随笔
  • 注:我会一步步分享实现的细节,若仍有问题联系我

开发环境

  • win10系统
  • qtcreator4.11.1
  • C++11
  • QT5.14.2

GitHub

  • GitHub下 的Log文件
  • 若不能访问GitHub,源码的资源包会随文章同步发布,免费下载
  • 资源包较GitHub更新不及时,请谅解

问题解决

  • Qt自定义日志类

需求

  • 输出日志信息到日志文件
  • 更新日志的修改日期
  • 日志文件超过一定大小备份老的创建新的
  • 删除一个月前的日志文件

结构

使用C++和QT实现Log自定义日志系统

使用C++和QT实现Log自定义日志系统文章来源地址https://www.toymoban.com/news/detail-750783.html

思路

  • 随便创建一个widget程序,放个测试按钮
  • 主要思路是使用 qInstallMessageHandler()接管qDebug(), qWarning()等调试信息,然后将信息流存储至本地日志文件,并管理日志文件
  • 先创建一个MyLog的类,在这里面我们实现自定义的日志系统
  • 这里依然是使用单例实现,整个程序的日志应该只能有一个
  • 首先实现单例getInstance获取MyLog的实例
  • 下面处理MyLog的构造函数,每一次启动日志系统,都要先设置日志文件的路径,然后更新修改日期,然后打开并备份老的日志文件,打开之后,每10分钟刷新日志文件,每1秒都将信息输出到日志,
  • 下面实现这个打开并备份老的日志文件的功能openAndBackupLogFile,这里我们的日志文件以天为单位,先处理一天内多次启动日志系统的情况,以追加的方式写入到日志文件里即可;如果程序运行的时候,日志系统的日期和程序运行日期不统一,同步日志日期为程序运行日期,生成新的日期日志,并且备份老的日志
  • 然后实现处理日志文件过大的问题,只要日志文件超限,备份老的,创建新的即可
  • 然后实现自动删除超时的日志文件,每次启动日志系统的时候,以当前时间为基准,计算出1个月前的时间,遍历日志目录下的所有日志文件,因为日志文件都以时间命名,删除超过1个月的日志文件即可
  • 最后,我们只需要处理信息函数即可,捕获系统中的各种输出信息,输出到文件即可

关键代码

MyLog.h

#ifndef MYLOG_H
#define MYLOG_H

#include <iostream>
#include <QDateTime>
#include <QMutexLocker>
#include <QDir>
#include <QTimer>
#include <QTextStream>


//最大保存文件大小
const int g_logLimitSize = 5;

class MyLog
{
public:
    MyLog();
    ~MyLog();

    static MyLog* getInstance();

    //消息处理函数
    static void messageHandler(QtMsgType type,
                                   const QMessageLogContext& context,
                                   const QString& msg);
public:
    //打开并备份之前的日志文件
    void openAndBackupLogFile();
    void checkLogFiles();
    void autoDeleteLog();
    //安装消息处理函数
    void installMessageHandler();

    //卸载消息处理函数,并释放资源
    void uninstallMessageHandler();
private:
    //日志文件夹目录
    QDir logDir;
    //重命名日志文件使用的定时器
    QTimer renameLogFileTimer;
    //刷新输出到日志文件的定时器
    QTimer flushLogFileTimer;
    //日志文件的创建时间
    QDate logFileCreateDate;

    //日志文件
    static QFile* logFile;
    //输出日志
    static QTextStream* logOut;
    //日志锁
    static QMutex logMutex;
    static QScopedPointer<MyLog> self;
};

#endif // MYLOG_H

MyLog.cpp

#include "mylog.h"
#include<QDebug>
#include<QTextCodec>

#define LOG 1
//初始化静态变量
QMutex MyLog::logMutex;
QFile* MyLog::logFile = NULL;
QTextStream* MyLog::logOut = NULL;
QScopedPointer<MyLog> MyLog::self;

//定义单例模式
MyLog* MyLog::getInstance()
{
    //还没有创建实例
    if(self.isNull())
    {
        //加把锁,只能有一个线程访问
        static QMutex mutex;
        //自动加解锁
        QMutexLocker locker(&mutex);
        //再次判断有没有实例,防止等待的时间中有线程获取到实例了
        if(self.isNull())
        {
            self.reset(new MyLog);
        }
    }
    return self.data();

}

MyLog::MyLog()
{
    //设置日志文件夹的路径,./exe
    logDir.setPath("log");
    //获取日志的绝对路径
    QString logPath = logDir.absoluteFilePath("today.log");

    //获取日志文件创建的时间
    //保存日志文件最后的修改时间
    logFileCreateDate = QFileInfo(logPath).lastModified().date();

    //打开并备份日志文件
    openAndBackupLogFile();

    //每10分钟检查一次日志文件创建的时间
    renameLogFileTimer.setInterval(1000 * 60 *1000);
    renameLogFileTimer.start();

    //处理超时事件,10分钟重复一次
    QObject::connect(&renameLogFileTimer,&QTimer::timeout,[this](){
        QMutexLocker locker(&MyLog::logMutex);
        openAndBackupLogFile();
        checkLogFiles();
        autoDeleteLog();
    });

    //定时刷新日志输出到日志文件,1秒1刷新
    flushLogFileTimer.setInterval(1000);
    flushLogFileTimer.start();

    QObject::connect(&flushLogFileTimer,&QTimer::timeout,[](){
#if LOG
        // 测试不停地写入当前时间到日志文件
        qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
#endif
        //刷新
        QMutexLocker locker(&MyLog::logMutex);
        if(NULL != logOut)
        {
            logOut->flush();
        }
    });
}

MyLog::~MyLog()
{
    if(NULL != logFile)
    {
        logFile->flush();
        logFile->close();
        logOut = NULL;
        logFile = NULL;
    }
}

//打开并备份之前的日志文件
void MyLog::openAndBackupLogFile()
{
    //有可能一天多次打开日志文件,使用追加的方式打开
    //目录不存在,创建目录
    if(!logDir.exists())
    {
        logDir.mkpath(".");
    }
    //log.txt的路径
    QString logPath = logDir.absoluteFilePath("today.log");

    //程序启动的时候,logfile为空
    if(logFile == NULL)
    {
        //创建新的
        logFile = new QFile(logPath);
        //只写,追加的方式打开日志文件
        //成功,创建文本流对象与日志文件关联,向日志文件写内容
        logOut = (logFile->open(QIODevice::WriteOnly | QIODevice::Text |QIODevice::Append)) ? new QTextStream(logFile) : NULL;

        if(logOut != NULL)
        {
            //设置编码格式
            logOut->setCodec("UTF-8");
        }

        //日志文件第一次创建,创建日期无效,设置为修改日期
        if(logFileCreateDate.isNull())
        {
            logFileCreateDate = QDate::currentDate();
        }
    }

    //程序运行的时候,创建日期不是当前日期,更新日期,重命名,备份老的并生成新的log.txt
    if(logFileCreateDate != QDate::currentDate())
    {
        //先刷新缓冲区,确保内容先输出到文件里
        logFile->flush();
        logFile->close();

        //更新日期到备份文件
        QString backUpLogPath = logDir.absoluteFilePath(logFileCreateDate.toString("yyyy-MM-dd.log"));;
        //备份原来的日志
        QFile::copy(logPath,backUpLogPath);
        //删除原来的日志文件
        QFile::remove(logPath);

        //创建新的log.txt,进行更新
        //只写,截断的方式打开日志
        logFile = new QFile(logPath);
        logOut = (logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) ? new QTextStream(logFile) : NULL;
        //更新为修改时间
        logFileCreateDate = QDate::currentDate();
        if(logOut != NULL)
        {
            logOut->setCodec("UTF-8");
        }
    }
}

//检查文件大小
void MyLog::checkLogFiles()
{
    //日志文件大小超过5m,备份并重新创建日志文件
    if(logFile->size() > 1024* g_logLimitSize)
    {
        //清空缓冲
        logFile->flush();
        logFile->close();

        QString logPath = logDir.absoluteFilePath("today.log");
        //备份老的日志文件
        QString backUplogPath = logDir.absoluteFilePath(logFileCreateDate.toString("yyyy-MM-dd.log"));
        QFile::copy(logPath,backUplogPath);
        QFile::remove(logPath);

        //创建新的日志文件
        logFile = new QFile(logPath);
        logOut = (logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) ? new QTextStream(logFile) :NULL;
        logFileCreateDate = QDate::currentDate();
        if(logOut != NULL)
        {
            logOut->setCodec("UTF-8");
        }
    }
}

//自动删除超过时间的日志文件
void MyLog::autoDeleteLog()
{
    //当前时间
    QDateTime now = QDateTime::currentDateTime();

    //基准,30天前
    QDateTime dateTime1 = now.addDays(-30);
    QDateTime dateTime2;

    QString logPath = logDir.absoluteFilePath("today.log");
    //打开日志目录
    QDir dir(logPath);
    //获取目录下的所有文件信息列表
    QFileInfoList fileList = dir.entryInfoList();
    foreach(QFileInfo f, fileList)
    {
        //跳过文件名为空的文件
        if(f.baseName() == "")
        {
            continue;
        }

        //将文件名解析为日期对象
        dateTime2 = QDateTime::fromString(f.baseName(),"yyyy-MM-dd");
        //大于30天,删除
        if(dateTime2 < dateTime1)
        {
            dir.remove(f.absoluteFilePath());
        }
    }
}


//定义消息处理函数
void MyLog::messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QMutexLocker locker(&MyLog::logMutex);
        QString level;

        switch (type) {
        case QtDebugMsg:
            level = "DEBUG";
            break;
        case QtInfoMsg:
            level = "INFO";
            break;
        case QtWarningMsg:
            level = "WARN";
            break;
        case QtCriticalMsg:
            level = "ERROR";
            break;
        case QtFatalMsg:
            level = "FATAL";
            break;
        default:
            break;
        }

#if defined (Q_OS_WIN)
        QByteArray localMsg = QTextCodec::codecForName("GB2312")->fromUnicode(msg);
#else
        QByteArray localMsg = msg.toLocal8Bit();
#endif

        //输出到控制台
        std::cout << std::string(localMsg) << std::endl;
        if(NULL == MyLog::logOut)
        {
            return;
        }

        //输出到日志文件
        //获取文件名,去掉路径
        QString fileName = context.file;
        int index = fileName.lastIndexOf(QDir::separator());
        fileName = fileName.mid(index + 1);

        //写入日志信息
        (*MyLog::logOut) << QString("%1 - [%2] (%3:%4, %5): %6\n")
                                        .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
                                        .arg(level)
                                        .arg(fileName)
                                        .arg(context.line)
                                        .arg(context.function)
                                        .arg(msg);
}

//安装
void MyLog::installMessageHandler()
{
    qInstallMessageHandler(MyLog::messageHandler);
}

//卸载
void MyLog::uninstallMessageHandler()
{
    qInstallMessageHandler(NULL);
}

到了这里,关于使用C++和QT实现Log自定义日志系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微信小程序定义并获取日志/实时log信息

    步骤一:开通实时日志 可以在开发者工具-详情-性能质量-实时日志,点击前往,在浏览器打开we分析界面: 也可登录小程序管理后台,点击统计进入we分析: 在we分析界面找到性能质量,打开实时日志,开通实时日志: 步骤二:定义实时日志对象,并记录日志 在js里定义实时

    2024年04月14日
    浏览(28)
  • 一文详细介绍查看和启用nginx日志(access.log和error.log),nginx错误日志的安全级别,自定义访问日志中的格式

    我们在实际工作中,经常使用到日志。 日志在一个系统中是非常重要的,它可以监控一个应用程序的活动,因为它们为你提供有用的调试信息,并使你能够分析一个 Web服务器 的所有方面。 像其他软件应用程序一样, Nginx 也会将诸如网站访问者、遇到的问题等事件保

    2024年02月09日
    浏览(39)
  • c++日志工具之——log4cpp

    Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下: 提供应用程序运行上下文,方便跟踪调试; 可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等; 可以动态控制日志记录级别,在效率和

    2024年02月13日
    浏览(30)
  • springboot 集成log4j日志,需要自定义json格式内容输出方便ES采集

    公司需要将服务迁移到K8S环境上,由于目前服务输出的格式不符合ES进行采集的日志格式,所有需要将日志输出的格式进行调整为JSON格式,方便ES采集 之前是直接配置的输出格式的message为 \\\"message\\\": %msg\\\" ,但是由于打日志需要打印json内容的日志就没有进行转义导致,整体输出

    2024年02月12日
    浏览(32)
  • Linux 系统 /var/log/journal/ 垃圾日志清理

    systemd-journald是一个改进型日志管理服务,可以收集来自内核、系统早期启动阶段的日志、系统守护进程在启动和运行中的标准输出和错误信息,还有syslog的日志。 systemd-journal 日志服务仅仅把日志集中保存在单一结构的日志文件/run/log中,由于日志是经历过压缩和格式化的二

    2024年02月16日
    浏览(26)
  • ELK日志系统设计方案-Log4j日志直推Kafka

    ELK 日志系统的常见解决方案: 通常的产品或项目部署至服务器,服务一般会打印日志便于线上问题跟踪。 使用 Log4j 中的自定义 Appender,将服务运行打印的日志直接推送到 Kafka 中。经由 Logstash 消费 Kafka 生产的数据,进行加工过滤后输出到 ElasticSearch 进行日志数据的存储与全

    2023年04月08日
    浏览(26)
  • Springboot配置Log4j日志系统,并将日志存入数据库

    Log4j是apache公司开发的一款日志管理系统,可以高效的管理系统中出现的BUG或者各种信息,并且可以已文本的方式或者数据库存入的方式来记录数据 在pom.xml中导入Log4j依赖 在Resources文件夹下创建一个log4j.properties文件 编写配置文件 这是个测试类 可以看见,控制台和数据库表

    2024年02月08日
    浏览(73)
  • 16-3_Qt 5.9 C++开发指南_使用QStyle 设置界面外观_实现不同系统下的界面效果的匹配

    Qt 是一个跨平台的类库,相同的界面组件在不同的操作系统上显示效果是不一样的。QStyle是封装了 GUI 界面组件外观的抽象类,Qt 定义了 QStyle 类的一些子类,应用于不同的操作系统如QWindowsStyle和QMacStyle 等。这些样式是 QtGUI 模块自带的,在不同的平台上编译运行的程序具有缺

    2024年02月13日
    浏览(40)
  • log4j日志框架的使用

    log4j的配置文件可以理解成有2部分 1根日志记录器  2 各appender(输出源)配置 入口 loggerManager的静态代码块 在loggerManager的静态代码块中,完成对配置文件的读取和解析 然后组装成框架的Logger对象、appender对象完成初始化操作 当调用logger.info打印日志时,和logback的流程基本一样

    2024年02月04日
    浏览(48)
  • [Android studio] 第2节 使用log打印日志

    目录 一、日志是什么? 二、使用方法 1.引入库 2.使用日志 3.使用详解 4.android.util.Log 在 Android Studio 中,日志是一个重要的工具,用于诊断应用程序的执行过程和调试应用程序中的问题。 在 Android Studio 中,日志是一个重要的工具,用于诊断应用程序的执行过程和调试应用程序

    2024年02月09日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包