qt浅谈之二十一log调试日志

jhcelue jhcelue     2022-08-31     336

关键词:

一、简单介绍

      近期因调试code时,想了解程序的流程,但苦于没有一个简易的日志记录,不停使用qDebug打印输出,而终于提交代码时得去多次删除信息打印,有时还会出现新改动的代码分不清是哪些部分。而使用#ifdef _DEBUG又比較烦这套,因此写了些简单的日志,方便排除问题,临时不能用于多线程中,以后须要再补充。

二、具体解释

1、追踪函数

#ifdef _DEBUG_PRINT
#define DEBUGPRINT DEBUGInfo printinfo(__FILE__, __LINE__, __FUNCTION__);
#else
#define DEBUGPRINT
#endif

class DEBUGInfo
{
public:
    DEBUGInfo(QString file, int line, QString func);
    ~DEBUGInfo();
    
private:
    QString fileName;
    int fileLine;
    QString funcName;
};
DEBUGInfo::DEBUGInfo(QString file, int line, QString func)
    :fileName(file)
    ,fileLine(line)
    ,funcName(func)
{
  QString result = "";
  QString beginTime = QDateTime::currentDateTime().toString("[yyyy-dd-MM hh:mm:ss.zzz] ");
  result += beginTime + "Enter:{" + fileName + ":" + QString::number(fileLine) + "---" + funcName + "}";
  qDebug() << result.toStdString().c_str();
}
DEBUGInfo::~DEBUGInfo()
{
  QString result = "";
  QString beginTime = QDateTime::currentDateTime().toString("[yyyy-dd-MM hh:mm:ss.zzz] ");
  result += beginTime + "Leave:{" + fileName + ":" + QString::number(fileLine) + "---" + funcName + "}";
  qDebug() << result.toStdString().c_str();
}

使用:在须要查看的函数中增加DEBUGPRINT就可以。输出文件名称,所在的行和函数名字。

void HelloWorld()
{
    DEBUGPRINT
}
技术分享

2、信息打印和写日志文件

enum LOGLEVEL{          
    LOG_DEBUG = 0,      /**< Debug >**/
    LOG_INFO,           /**< Info >**/
    LOG_WARN,           /**< Warn >**/
    LOG_ERROR           /**< Error >**/
};
class LogWriter{
    public:
        static LogWriter* getLogCenter();
        void PrintLog(LOGLEVEL level, const char* msg, ...);
        void SaveFileLog(LOGLEVEL level, const char* msg, ...);
        void setLogPath(QString logPath);         //defalut: current path
        void setLogLevel(LOGLEVEL logLevel);      //defalut: LOG_DEBUG
    private:
        static LogWriter * _logCenter;
        explicit LogWriter();
        ~LogWriter();
    private:
        QString _logPath;
        LOGLEVEL _logLevel;
    private:
        QString getLevelStr(LOGLEVEL level);
};
LogWriter *LogWriter::getLogCenter()
{
    if (_logCenter == NULL)
        _logCenter = new LogWriter;
    return _logCenter;
}

LogWriter::LogWriter()
{
    _logLevel = LOG_DEBUG;
    _logPath = QDir::currentPath();
}

LogWriter::~LogWriter()
{
    if (_logCenter) {
        delete _logCenter;
        _logCenter = NULL;
    }
}

void LogWriter::PrintLog(LOGLEVEL level, const char *msg,  ...)
{
    if (level < _logLevel)  return;     //low level
    char logBuffer[8192] = {0};
    va_list vl_fmt;                     //buffer
    va_start(vl_fmt, msg);
    vsprintf(logBuffer, msg, vl_fmt);
    va_end(vl_fmt);

    QString fileTime = "";
    QString logTime = "";
    QString logLevel = getLevelStr(level);
    fileTime = QDateTime::currentDateTime().toString("yyyyddMM");
    logTime = QDateTime::currentDateTime().toString("yyyy-dd-MM hh:mm:ss.zzz");
    qDebug("[%s] [%s] {%s}", logTime.toStdString().c_str(), logLevel.toStdString().c_str(), logBuffer);
}

void LogWriter::SaveFileLog(LOGLEVEL level, const char *msg,  ...)
{
    if (level < _logLevel)  return;  //low level
    char logBuffer[8192] = {0};
    va_list vl_fmt;                  //buff
    va_start(vl_fmt, msg);
    vsprintf(logBuffer, msg, vl_fmt);
    va_end(vl_fmt);

    QString logTime = "";
    QString fileTime = "";
    fileTime = QDateTime::currentDateTime().toString("yyyyddMM");
    logTime = QDateTime::currentDateTime().toString("[yyyy-dd-MM hh:mm:ss.zzz]");
    QString logLevel = getLevelStr(level);
    QString logFile = _logPath;
    if (logFile.right(1) != "/") {
        logFile += "/";
    }
    QDir mDir(logFile);
    if (!mDir.exists()) {
        mDir.mkpath(logFile);
    }
    logFile += "isoft_";
    logFile += fileTime;
    logFile += ".log";

    QFile file(logFile);
    file.open(QIODevice::ReadWrite | QIODevice::Append | QIODevice::Text);
    QTextStream out(&file);
    out << logTime << " [" << logLevel << "] " << "{" << logBuffer << "}" << endl;
    file.close();
}

QString LogWriter::getLevelStr(LOGLEVEL level)
{
    switch(level) {
        case LOG_DEBUG: return "LOG_DEBUG"; break;
        case LOG_INFO: return "LOG_INFO"; break;
        case LOG_WARN: return "LOG_WARN"; break;
        case LOG_ERROR: return "LOG_ERROR"; break;
    }
}

void LogWriter::setLogPath(QString logPath)
{
    _logPath = logPath;
}

void LogWriter::setLogLevel(LOGLEVEL logLevel)
{
    _logLevel = logLevel;
}
能够设置日志的级别和日志文件的路径。

在函数中使用:

LogWriter::getLogCenter()->PrintLog(LOG_DEBUG, "hello world");
LogWriter::getLogCenter()->PrintLog(LOG_INFO, "%s:%s,%d", "hello", "world", 1234);
LogWriter::getLogCenter()->SaveFileLog(LOG_WARN, "hello world");
LogWriter::getLogCenter()->SaveFileLog(LOG_ERROR, "%s:%s,%d", "hello", "world", 1234);

技术分享

也会在当前路径下生成文件。

3、Qt自带样例

Qt官方样例:

 #include <qapplication.h>
 #include <stdio.h>
 #include <stdlib.h>

 void myMessageOutput(QtMsgType type, const char *msg)
 {
     switch (type) {
     case QtDebugMsg:
         fprintf(stderr, "Debug: %s
", msg);
         break;
     case QtWarningMsg:
         fprintf(stderr, "Warning: %s
", msg);
         break;
     case QtCriticalMsg:
         fprintf(stderr, "Critical: %s
", msg);
         break;
     case QtFatalMsg:
         fprintf(stderr, "Fatal: %s
", msg);
         abort();
     }
 }

 int main(int argc, char **argv)
 {
     qInstallMsgHandler(myMessageOutput);
     QApplication app(argc, argv);
     ...
     return app.exec();
 }
自己定义改动:
void outputMessage(QtMsgType type, const char *msg)
{
    static QMutex mutex;
    mutex.lock();

    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:");
        abort();
    }
    QString message = QString("[%1] %2 %3").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd")).arg(text).arg(msg);

    QFile file("log.txt");
    file.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream text_stream(&file);
    text_stream << message << endl;
    file.flush();
    file.close();

    mutex.unlock();
}
qInstallMsgHandler(outputMessage);
qWarning("This is a warning message");
qCritical("This is a critical message");
//qInstallMsgHandler(0)    //To restore the message handler, call
执行结果:
技术分享

三、总结

(1)本文仅仅是一个简单的日志记录。还能够设计成异步的多线程式的,甚至能够增加到线程池,对性能要求较高的系统还得考虑文件的大小控制、存储空间的控制、文件的级别控制、文件的日期控制和自己主动清除等操作。
(2)本人思路有限,若有更好的设计建议。也可发邮件沟通,在此先感谢。邮箱地址[email protected]









qt基础之二十一:qtro(qtremoteobject)实现进程间通信

这里将QtRO单独从上一篇Qt基础之二十:进程间通信拎出来,因为它是Qt5.9以后新加入的模块,专门用于进程间通信。其使用步骤有点类似之前介绍过的RPC(RemoteProcedureCall)框架:gRPC和thrift,关于这两个框架详见Qt中调用thrift和Qt... 查看详情

qt基础之二十一:qtro(qtremoteobject)实现进程间通信

这里将QtRO单独从上一篇Qt基础之二十:进程间通信拎出来,因为它是Qt5.9以后新加入的模块,专门用于进程间通信。其使用步骤有点类似之前介绍过的RPC(RemoteProcedureCall)框架:gRPC和thrift,关于这两个框架详见Qt中调用thrift和Qt... 查看详情

webrtc笔记之二十一:基于websocketpp的janus客户端

...1.浏览器与Janus客户端2.两个Janus客户端二.实现在WebRTC笔记之二十:Janus信令交互流程介绍了信令的交互,这里只需用WebSocketPP来收发这些信令即可。WebRT 查看详情

java经典编程题50道之二十一

求1+2!+3!+...+20!的和。publicclassExample21{   publicstaticvoidmain(String[]args){      sum(20);   }   publicstaticvoidsum(intn){ 查看详情

qt浅谈之四十二钟表摆动显示百分比

一、简介       Qt下利用定时器实现指针指示百分比的钟摆的动态显示效果,可以适用于显示百分比或进度条的进度或时间的刻度值(在圆形进度条上的一种改进)。效果如下:二、详解1、代码(1)Dashb... 查看详情

css学习(二十一)-flexbox模型之二

一、理论:1.flex-flowa.flex-direction设置伸缩容器的伸缩流方向b.flex-wrap设置伸缩容器中的伸缩项目在伸缩容器无足够空间时,伸缩项目在伸缩容器中是否换行排列2.flex-packa.具有与box-pack属性相同的参数b.distribute伸缩项目会平均分布... 查看详情

px4模块设计之二十一:uorb消息管理模块(代码片段)

PX4模块设计之二十一:uORB消息管理模块1.uORB模块构建模式2.uORB消息管理函数2.1状态查询2.2资源利用2.3模块启动2.4模块停止3.uORB消息接口3.1消息主题注册3.2消息主题去注册3.3消息主题发布3.4消息主题订阅3.5消息主题去订阅3.6设... 查看详情

unityhtframework框架(二十一)debug调试器(代码片段)

更新日期:2019年10月15日。Github源码:[点我获取源码]Gitee源码:[点我获取源码]索引Debug调试器简介使用Debug启用Debugger调试器Debugger调试器面板FPS帧率监控Console[控制台日志]Scene[场景]Hierarchy[层级]Inspector[检视]定义调试... 查看详情

qt基础之二十:进程间通信

目录一.常用Qt进程间通信方式二.管道(QLocalServer、QLocalSocket)1.QLocalServer2.QLocalSocket3.一个例子 查看详情

mfc编程入门之二十一(常用控件:编辑框editcontrol)

  上一节讲了静态文本框,本节讲的是编辑框(EditControl)同样是一种很常用的控件,我们可以在编辑框中输入并编辑文本。在前面加法计算器的例子中已经演示了编辑框的基本应用。下面具体讲解编辑框的使用。  编辑框... 查看详情

qt开发(二十一)——qt布局管理器

QT开发(二十一)——QT布局管理器一、布局管理器简介    QT中使用绝对定位的布局方式无法自适应窗口的变化。    QT中提供了对界面组件进行布局管理的类,用于对界面组件进行管理,能够自动排... 查看详情

大数据nifi(二十一):监控日志文件生产到kafka

文章目录监控日志文件生产到Kafka一、​​​​​​​​​​​​​​配置“TailFile”处理器 查看详情

qt基础之二十三:反射(reflection)(代码片段)

反射是指程序在运行时动态获取对象属性与方法的一种机制,即编译器需要将类型信息(属性类型与偏移地址以及成员函数的地址等信息)编译到程序文件中,当程序运行时将这些信息加载到内存中去,做到运行时只根据对象的地... 查看详情

游戏制作大致流程粗谈之二

上次讲到了游戏原画的制作,在原画师完成原画的创作后,负责建模的同学便需要通过建模工具对原画进行建模,包括游戏的人物模型,场景,物品,等等等等,游戏建模大致流程如下:1.建立模型  2.UV展开3.绘制贴图4.... 查看详情

zabbix监控系统系列之二十一:监控海康威视摄像头

参考技术A配置摄像头登录摄像头Web页面-配置-网络-高级配置-SNMP启用SNMPv2c设置读团体名设置写团体名设置trap地址为zabbix地址保存创建主机1配置主机主机名称:输入摄像头主机名可见名称:别名群组:选择群组Interfaces:使用SNMPI... 查看详情

qt基础之二十六:qt绘图系统(paintsystem)

Qt的绘图系统允许使用相同的API在屏幕和其它打印设备上进行绘制。整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类。QPainter用来执行绘制的操作;QPaintDevice是一个二维空间的抽象,这个二维空间允许QPainter在其上面进行... 查看详情

浅谈之merge-sort-join

初接触执行计划,做练习时执行sql(如图一)图一:查看其执行计划(如图二)图二:看到上面这个执行计划用到mergesortjoin(排序合并联合查询),刚开始没有理解为什么这条执行计划里还有sortjoin,emp表里deptno字段不是已经有... 查看详情

filebeat与kibana仪表板(二十一)(代码片段)

  Filebeat附带了示例Kibana仪表板,可视化文件,并提供了搜索以可视化Kibana中的Filebeat数据。  本例展示Nginx示例仪表板步骤一、采集Nginx日志  使用FilebeatNginxModule采集NginxAccess日志  参考:【Beats】Filebeat收集Nginx日志(... 查看详情