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

一、简介

最近因调试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);

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

三、总结

(1)本文只是一个简单的日志记录,还可以设计成异步的多线程式的,甚至可以加入到线程池,对性能要求较高的系统还得考虑文件的大小控制、存储空间的控制、文件的级别控制、文件的日期控制和自动清除等操作。

(2)本人思路有限,若有更好的设计建议,也可发邮件沟通,在此先感谢!邮箱地址[email protected]。

时间: 2024-10-24 09:26:44

Qt浅谈之二十一log调试日志的相关文章

Qt浅谈之二十App自动重启及关闭子窗口(六种方法)

一.简介 最近因项目需求,Qt程序一旦检测到错误,要重新启动,自己是每次关闭主窗口的所有子窗口但有些模态框会出现问题,因此从网上总结了一些知识点,以备以后的应用. 二.详解 1.Qt结构 [cpp] view plaincopy int main(int argc, char *argv[]) { QApplication a(argc, argv); MyWidget w; MyDialog dialog;                      //新建MyDialog类对象 if(dia

Qt浅谈之二十七进程间通信之QtDBus

一.简介 DBus的出现,使得Linux进程间通信更加便捷,不仅可以和用户空间应用程序进行通信,而且还可以和内核的程序进行通信,DBus使得Linux变得更加智能,更加具有交互性.        DBus分为两种类型:system bus(系统总线),用于系统(Linux)和用户程序之间进行通信和消息的传递:session bus(回话总线),用于桌面(GNOME, KDE等)用户程序之间进行通信. 二.详解之Qt代码 1.代码一 (1)test.h [html] view plain copy

Qt浅谈之二十App自动重启及关闭子窗口

一.简介 最近因项目需求,Qt程序一旦检测到错误,要重新启动,自己是每次关闭主窗口的所有子窗口但有些模态框会出现问题,因此从网上总结了一些知识点,以备以后的应用. 二.详解 1.Qt结构 [cpp] view plain copy int main(int argc, char *argv[]) { QApplication a(argc, argv); MyWidget w; MyDialog dialog;                      //新建MyDialog类对象 if(di

Qt浅谈之二:钟表(时分秒针),QSplitter实现自由伸缩滑动窗口 good

http://blog.csdn.net/taiyang1987912/article/details/30272105 http://blog.csdn.net/taiyang1987912/article/details/50717179 http://blog.csdn.net/taiyang1987912/article/category/2314763

Qt浅谈之十六:TCP和UDP(之一)

一.简介 Qt使用QtNetwork模块来进行网络编程,提供了一层统一的套接字抽象用于编写不同层次的网络程序,避免了应用套接字进行网络编的繁琐(因有时需引用底层操作系统的相关数据结构).有较底层次的类如QTcpSocket.QTcpServer和QUdpSocket等来表示低层的网络概念:还有高层次的类如QNetworkRequest.QNetworkReply和QNetworkAccessManager使用相同的协议来执行网络操作:也提供了QNetworkConfiguration.QNetw

Qt浅谈内存泄露(总结)

Qt浅谈内存泄露(总结) 来源 http://blog.csdn.net/taiyang1987912/article/details/29271549 一.简介 Qt内存管理机制:Qt 在内部能够维护对象的层次结构.对于可视元素,这种层次结构就是子组件与父组件的关系:对于非可视元素,则是一个对象与另一个对象的从属关系.在 Qt 中,在 Qt 中,删除父对象会将其子对象一起删除. C++中delete 和 new 必须配对使用(一 一对应):delete少了,则内存泄露,多了麻烦更大.Qt中使用

浅谈DevExpress&lt;二&gt;:设计一个完整界面(2)

下面来把剩下的工作做完,换肤功能昨天已近讨论过,今天就不重复了.首先建立三个全局变量,一个存放文件路径,一个存放数据,一个存放过滤条件. string DBFileName; DataView dataView; string[] filter = new string[3]; 取得数据并绑定到表格中: DBFileName = DevExpress.Utils.FilesHelper.FindingFileName(Application.StartupPath, "Products.xml&

浅谈DevExpress&lt;二&gt;:设计一个完整界面(1)

昨天谈了界面的换肤问题,今天拿一个简单的界面来介绍一下怎么设计一个五脏俱全的界面,总体效果如下图(种类的图片随便找的^^): 创建一个winform项目,在上面拉进去一个bar管理器和图片列表: 在菜单栏.工具栏和状态栏中,分别加入菜单.编辑栏.按钮和静态文本: 菜单栏改名并设置好图片: 然后改工具栏项的属性,拿第一个举个例子,后面的大同小异,选择EditItem后先将其PaintStyle属性改为CapationGlyph,然后找到Edit,选择CheckEdit,就会变成下面的样子: 依法炮

浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色

浅谈SQL Server中的事务日志(二)----事务日志在修改数据时的角色 本篇文章是系列文章中的第二篇,以防你还没有看过第一篇.上一篇的文章地址如下: 浅谈SQL Server中的事务日志(一)----事务日志的物理和逻辑构架 简介 每一个SQL Server的数据库都会按照其修改数据(insert,update,delete)的顺序将对应的日志记录到日志文件.SQL Server使用了Write-Ahead logging技术来保证了事务日志的原子性和持久性.而这项技术不仅仅保证了ACID