Qt实现记录日志文件log

2023-05-16

概述

Qt有两种实现记录日志的方式,第一种是安装自定义的Qt消息处理程序,自动输出程序产生的调试消息、警告、关键和致命错误消息的函数;第二种是自定义一个类,可以在程序指定位置打印输出指定的内容。

第一种qInstallMessageHandler方式

自定义消息处理函数,然后安装该函数,注意此时QDebug的消息将会输出在日志文件,Qt程序调式时不再打印。
main.cpp

#include "widget.h"
#include <QApplication>
#include <QMutex>
#include <QFile>
#include <QMessageLogContext>
#include <QDebug>
#include <QDateTime>

void outputMessage(QtMsgType type,const QMessageLogContext &context,const QString &msg);
int main(int argc, char *argv[])
{
    qInstallMessageHandler(outputMessage);//安装消息处理程序
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

void outputMessage(QtMsgType type,const QMessageLogContext &context,const QString &msg)
{
    static QMutex mutex;
    mutex.lock();
    QByteArray localMsg = msg.toLocal8Bit();
    QString text;
    switch (type)
    {
        case QtDebugMsg:
            text = QString("Debug:");
            break;
        case QtWarningMsg:
            text = QString("Warning:");
            break;
        case QtCriticalMsg:
            text = QString("Critical:");
            break;
        case QtFatalMsg:
            text = QString("Fatal:");
            break;
        default:
            text = QString("Debug:");
    }

    // 设置输出信息格式
       QString context_info = QString("File:(%1) Line:(%2)").arg(QString(context.file)).arg(context.line); // F文件L行数
       QString strDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
       //QString strMessage = QString("%1 %2 \t%3 \t%4").arg(text).arg(context_info).arg(strDateTime).arg(msg);
       QString strMessage = QString("%1 \t%2 \t%3").arg(text).arg(strDateTime).arg(msg);
       // 输出信息至文件中(读写、追加形式)
       QFile file(QString(QDateTime::currentDateTime().toString("yyyy-MM-dd").append("-log.txt")));
       file.open(QIODevice::ReadWrite | QIODevice::Append);
       QTextStream stream(&file);
       stream << strMessage << "\r\n";
       file.flush();
       file.close();
       // 解锁
        mutex.unlock();
}

第二种:自定义一个类,实现输出日志接口

定义一个日志类,实现输出日志到指定文件的接口,在需要输出日志的地方调用接口即可。
clog.h

#ifndef CLOG_H
#define CLOG_H

#include <QFile>

class  CLog : public QObject
{
    Q_OBJECT
public:

    /*!
     *  @brief 日志等级
     */
    enum CLOG_LEVEL
    {
        RINFO,               /*!<    提示  */
        RWARNING,            /*!<    警告  */
        RERROR               /*!<    错误  */
    };
    Q_FLAG(CLOG_LEVEL)

    struct LogConfig
    {
        bool isRecord2File;     /*!< 是否记录到文件 */
        int level;              /*!< 记录日志等级,大于等于此level的日志将被记录 */
    };

    CLog();

    void setLogLevel(const CLog::CLOG_LEVEL & level);
    CLog::CLOG_LEVEL getLogLevel(){return logLevel;}

    static bool init(CLog::LogConfig & logConfig);
    static bool createDir(QString dirPath);

    static void log(CLOG_LEVEL nLevel,const char * fileDesc,const char * functionDesc, int lineNum,const char* data, ...);

private:
    static QString getLeveDesc(CLOG_LEVEL level);

private:
    static bool isRecord2File;
    static bool isFileReady;
    static CLOG_LEVEL logLevel;
};

#ifdef Q_OS_WIN
#define FILE_SEPARATOR '\\'
#else
#define FILE_SEPARATOR '/'
#endif

#define FUNC_SEPARATOR '::'

#ifndef QT_NO_DEBUG
#define __FILENAME__ (strrchr(__FILE__, FILE_SEPARATOR) ? (strrchr(__FILE__, FILE_SEPARATOR) + 1):__FILE__)
#define __FUNNAME__ (strrchr(__FUNCTION__,FUNC_SEPARATOR)?(strrchr(__FUNCTION__, FUNC_SEPARATOR) + 1):__FUNCTION__)
#else
#define __FILENAME__ NULL
#define __FUNNAME__ NULL
#endif

#define CLOG_INFO(...)       CLog::log(CLog::RINFO,__FILENAME__,__FUNNAME__,__LINE__, __VA_ARGS__)
#define CLOG_WARNING(...)    CLog::log(CLog::RWARNING, __FILENAME__,__FUNNAME__, __LINE__,__VA_ARGS__)
#define CLOG_ERROR(...)      CLog::log(CLog::RERROR,__FILENAME__,__FUNNAME__,__LINE__,__VA_ARGS__)

#endif // CLOG_H

clog.cpp

#include "clog.h"

#include <QApplication>
#include <QDir>
#include <QDate>
#include <QMetaEnum>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <stdarg.h>

#include <QDebug>

const char PATH_LogPath[] = "/../logs";
const char Suffix[] = ".log";

#define MAX_LOG_LENGH 1024

bool CLog::isFileReady = false;
bool CLog::isRecord2File = true;
CLog::CLOG_LEVEL CLog::logLevel = CLog::RINFO;           //默认是info级

QFile localFile;
QMutex mutex;

CLog::CLog()
{
}

void CLog::setLogLevel(const CLog::CLOG_LEVEL &level)
{
    logLevel = level;
}

bool CLog::init(LogConfig &logConfig)
{
    isRecord2File = logConfig.isRecord2File;
    logLevel = (CLog::CLOG_LEVEL)logConfig.level;

    QString logDir = qApp->applicationDirPath() +  QString(PATH_LogPath);
    if(createDir(logDir))
    {
        QString fileName = logDir + QDir::separator() + QDate::currentDate().toString("yyyy-MM-dd") + QString(Suffix);
        localFile.setFileName(fileName);
        if(localFile.open(QFile::WriteOnly|QFile::Append|QFile::Text))
        {
            isFileReady = true;
        }
    }
    return isFileReady;
}

bool CLog::createDir(QString dirPath)
{
    QFileInfo fileInfo(dirPath);
    if(!fileInfo.exists())
    {
        QDir tmpDir;
        return tmpDir.mkpath(dirPath);
    }

    return true;
}

void CLog::log(CLOG_LEVEL nLevel, const char *fileDesc, const char *functionDesc, int lineNum, const char* data, ...)
{
    QMutexLocker locker(&mutex);
    if(isFileReady && nLevel >= logLevel)
    {
        QString recordInfo = QString("[%1]").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz"));
        recordInfo.append(getLeveDesc(nLevel));

#ifndef QT_NO_DEBUG
        recordInfo.append(QString("[%1:%2:%3]").arg(fileDesc).arg(functionDesc).arg(lineNum));
#endif
        va_list vlist;
        va_start(vlist,data);

        QByteArray byteArray;
#if defined(Q_OS_WIN)
        int recordLen = _vscprintf(data,vlist);
        byteArray.resize(recordLen);
#else
        byteArray.resize(1024);
#endif
        vsprintf(byteArray.data(),data,vlist);
        recordInfo.append(byteArray);
        va_end(vlist);

        recordInfo.append("\n");

        if(isRecord2File){
            localFile.write(recordInfo.toLocal8Bit().data(),recordInfo.toLocal8Bit().length());
            localFile.flush();
        }else{
//            qDebug()<<recordInfo;
        }
    }
}

QString CLog::getLeveDesc(CLog::CLOG_LEVEL level)
{
#if (QT_VERSION > 0x050500)
    static QMetaEnum metaEnum = QMetaEnum::fromType<CLog::CLOG_LEVEL>();
    return QString("[%1]").arg(metaEnum.key(level));
#else
    switch(level)
    {
        case CLOG_LEVEL::INFO:
                                return "[INFO]";
        case CLOG_LEVEL::INFO:
                                return "[WARNING]";
        case CLOG_LEVEL::INFO:
                                return "[ERROR]";
    }
#endif
}

简单调用示例:

    CLog::LogConfig logConfig;
    logConfig.isRecord2File = true;
    logConfig.level = 0;
    CLog::init(logConfig);
    CLOG_INFO("df2008");

输出日志:
[2020-12-03 13:15:14:549][RINFO][widget.cpp:Widget:17]df2008

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt实现记录日志文件log 的相关文章

随机推荐

  • c语言 一个字节bit对换,请问在C语言中,如何高效把一字节的位对换(bit0和bit7,bit1和bit6,bit2和bit5,bit3和b...

    回复 114 请问在C语言中 xff0c 如何高效把一字节的位对换 bit0和bit7 bit1和bit6 bit2和bit5 bit3和b 积分 精华汤圆游客 393007870 出0入0汤圆 电梯直达 发表于 2008 12 2 10
  • studio one 3 机架声道设置_Lenovo UC30 声卡驱动跳线VST机架跳线

    只要是支持ASIO的声卡 xff0c 都可以使用宿主机架软件 xff0c 而机架设置好ASIO后 xff0c 还需要设置一下 xff0c 也就是设置麦克风 音乐的输入和麦克风的人声进入到经由机架挂载的效果插件 xff0c 调试后的混音的输出
  • Linux大小端转换实现

    实现 include lt byteswap h gt include lt stdint h gt 64 brief 8字节类型的字节序转化 template lt class T gt typename std enable if lt
  • Vins-Mono 论文 && Coding 一 7(2). pose_graph: 回环检测 && 重定位

    一 处理关键帧流程 void PoseGraph addKeyFrame KeyFrame cur kf bool flag detect loop 1 shift to base frame 将当前帧 pose 转换到 drift fre
  • 浅谈STM32串口通信(一)基本介绍和一个字节传输的实现

    文章目录 0 传输引脚1 传输一个字节1 1 发送一个字节1 2 接收一个字节 2 代码2 1 配置2 2 发送一个字节2 3 接收一个字节 0 传输引脚 串口收发共需要三根线 其中 TX脚为发送引脚 RX脚为发送引脚 GND为地 作为电平
  • 图像融合(Image Fusion)简介

    图像融合 Image Fusion 是用特定的算法将两幅或多幅图像综合成一幅新的图像 融合结果由于能利用两幅 或多幅 图像在时空上的相关性及信息上的互补性 xff0c 并使得融合后得到的图像对场景有更全面 清晰的描述 xff0c 从而更有利
  • IP地址分类

    大家好呀 xff0c 我是请假君 xff0c 今天又来和大家一起学习数通了 xff0c 今天要分享的知识是IP地址的分类 各个网段内具有的IP节点数各不相同 xff0c 为了适应这种需求 xff0c IP地址被分成五类 1 A类IP地址的第
  • 解决映射网络驱动器自动断开问题

    解决映射网络驱动器自动断开问题 hzq0201 2012 04 13 06 47 36 2777 收藏 2 版权 映射的网络驱动器在一段时间自动断开 xff0c 是由于服务器服务自动断开连接功能的默认超时期限造成的 xff0c 我们可以通过
  • vector深度探索

    声明 xff1a 本文中所有图件都来自B站侯捷老师授课视频 vecctor 底层实现原理 图1 GNU2 9 实现的容器vector vector 的内存是动态增长的 xff0c vector 最重要的三个成员变量为 三个迭代器 xff1a
  • 发送一个http请求以及url三部分组成和语法

    浏览器从URL中解析出服务器的主机名浏览器讲服务器的主机名转化成服务器的IP地址 xff08 DNS解析 xff09 浏览器将端口号从URL解析出来浏览器建立一条鱼web服务器的TCP连接浏览器向服务器发送一条http请求报文服务器向浏览器
  • 结构体对齐规则

    结构体 xff1a 结构体 xff08 struct xff09 是由一系列具有相同类型或不同类型的数据构成的集合 因为这一特性 xff0c 方便了开发者在使用的过程中可以将需要的不同的数据类型放在一起 xff0c 做成我们需要的数据类型
  • GPS坐标用于机器人定位的简单处理

    文章目录 前言一 GPS数据格式二 GPS坐标转换二维坐标原理三 参考代码1 转换经纬度格式2 解析通过串口获得的NMEA数据3 将经纬度转换为xy平面二维坐标 前言 最近工作上面接触使用GPS的NMEA数据为机器人提供平面坐标定位 xff
  • 学完C++基础后再学什么?

    学完 xff1f 那是什么程度 xff1f STL用得熟练吗 xff1f 算法和数据结构掌握得怎么样呢 xff1f 会写界面吗 xff1f BOOST呢 xff1f 像楼上所说的换一种语言 xff0c 简直是痴人说梦 xff0c 如果不深入
  • 视觉SLAM十四讲:回环检测-知识点+代码

    目录 基于外观的几何关系1 基础知识1 1 准确率和召回率1 2 词袋模型1 3 字典1 4 字典的数据结构1 5 相似度的计算1 6 相似度评分的处理1 7 检测回环后的验证 2 实践与代码解析2 1 创建字典2 2 相似度计算 回环检测
  • QT笔记--QT内类的层次关系,以及控件从属关系

    QT窗口界面使用的类层次如下 只包含了直接使用部分 界面上每一个创建的控件 xff0c 都是一个控件类的对象 xff0c 定义在头文件ui mainwindoow h的类UI MainWindow中 xff0c 并且其中的成员函数setup
  • C_带参数的宏定义

    C 带参数的宏定义 xff23 语言允许宏带有参数 在宏定义中的参数称为形式参数 xff0c 在宏调用中的参数称为实际参数 对带参数的宏 xff0c 在调用中 xff0c 不仅要宏展开 xff0c 而且要用实参去代换形参 带参宏定义的一般形
  • 十进制数转换成十六进制数~C语言

    include lt stdio h gt 下面将整数a转换成十六进制输出的字符串 原理 xff1a 1 xff0c 首先知道0b100000 61 0b10000 2 61 0b1000 2 61 0b100 2 61 0b10 2 利用
  • Qt实现线程安全的单例模式

    实现方式 1 实现单例 把类的构造函数 拷贝构造函数 赋值操作符定义为private的 xff1b 把获取单例的接口和唯一的实例指针定义为static的 xff0c 不需要实例化 xff0c 直接通过类名即可访问 2 支持多线程 采用双重校
  • 文本文件和二进制文件的差异和区别

    广义上的二进制文件包括文本文件 xff0c 这里讨论的是狭义上的二进制文件与文本文件的比较 xff1a 能存储的数据类型不同 文本文件只能存储char型字符变量 二进制文件可以存储char int short long float 各种变量
  • Qt实现记录日志文件log

    概述 Qt有两种实现记录日志的方式 xff0c 第一种是安装自定义的Qt消息处理程序 xff0c 自动输出程序产生的调试消息 警告 关键和致命错误消息的函数 xff1b 第二种是自定义一个类 xff0c 可以在程序指定位置打印输出指定的内容