一、简单介绍

近期因调试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
}

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGFpeWFuZzE5ODc5MTI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

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);

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGFpeWFuZzE5ODc5MTI=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

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

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\n", msg);
break;
case QtWarningMsg:
fprintf(stderr, "Warning: %s\n", msg);
break;
case QtCriticalMsg:
fprintf(stderr, "Critical: %s\n", msg);
break;
case QtFatalMsg:
fprintf(stderr, "Fatal: %s\n", 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

执行结果:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

三、总结

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

(2)本人思路有限,若有更好的设计建议。也可发邮件沟通,在此先感谢。邮箱地址yang.ao@i-soft.com.cn。

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

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

    一.简介 DBus的出现,使得Linux进程间通信更加便捷,不仅可以和用户空间应用程序进行通信,而且还可以和内核的程序进行通信,DBus使得Linux变得更加智能,更加具有交互性.        DB ...

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

    一.简介 最近因项目需求,Qt程序一旦检测到错误,要重新启动,自己是每次关闭主窗口的所有子窗口但有些模态框会出现问题,因此从网上总结了一些知识点,以备以后的应用. 二.详解 1.Qt结构 int ma ...

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

    一.简介 最近因项目需求,Qt程序一旦检测到错误,要重新启动,自己是每次关闭主窗口的所有子窗口但有些模态框会出现问题,因此从网上总结了一些知识点,以备以后的应用. 二.详解 1.Qt结构 int ma ...

  4. Qt浅谈之二十六图片滑动效果

    一.简介 博客中发现有作者写的仿360的代码,觉得其中图片滑动的效果很有意思,特提取其中的代码.并加上类似mac的画面移动的动画效果. 二.详解 1.代码一:界面滑动(QWidget) (1)slid ...

  5. Qt浅谈之二:钟表(时分秒针)

    一.简介 QT编写的模拟时钟,demo里的时钟只有时针和分针,在其基础上添加了秒针,构成了一个完整的时钟.能对2D绘图中坐标系统.平移变换(translate).比例变换(scale).旋转变换(ro ...

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

    一.简介 DBus的出现,使得Linux进程间通信更加便捷,不仅可以和用户空间应用程序进行通信,而且还可以和内核的程序进行通信,DBus使得Linux变得更加智能,更加具有交互性.        DB ...

  7. Qt浅谈内存泄露(总结)

    Qt浅谈内存泄露(总结) 来源 http://blog.csdn.net/taiyang1987912/article/details/29271549 一.简介 Qt内存管理机制:Qt 在内部能够维 ...

  8. Qt浅谈之总结(整理)

    Qt浅谈之总结(整理) 来源 http://blog.csdn.net/taiyang1987912/article/details/32713781 一.简介 QT的一些知识点总结,方便以后查阅. ...

  9. Android开发-浅谈架构(二)

    写在前面的话 我记得有一期罗胖的<罗辑思维>中他提到 我们在这个碎片化 充满焦虑的时代该怎么学习--用30%的时间 了解70%该领域的知识然后迅速转移芳草鲜美的地方 像游牧民族那样.原话应 ...

随机推荐

  1. angular 组件之间传值

    /** * Created by Administrator on 2017/8/28. */ var app =angular.module('app',[]); app.directive('fo ...

  2. Oracle审计相关对象的迁移

    目录 创建审计用的表空间 在线迁移 查询结果 在日常的数据库维护中,经常出现因为数据库登录审计的功能启动,导致system表空间被用满.从而出现异常,一般建议把aud$相关对象迁移到其他表空间,从而避 ...

  3. Charles-安装和配置

    一. 安装.破解charles工具 1. 安装压缩包中的charles_setup.exe,安装完成后先不启动charles. 2. 在安装文件中找到crack文件,将文件中的charles.jar拷 ...

  4. 九度oj 题目1201:二叉排序树

    题目描述: 输入一系列整数,建立二叉排序数,并进行前序,中序,后序遍历. 输入: 输入第一行包括一个整数n(1<=n<=100).    接下来的一行包括n个整数. 输出: 可能有多组测试 ...

  5. ICMP TYPE CODE

    TYPE CODE Description Query Error 0 0 Echo Reply——回显应答(Ping应答) x   3 0 Network Unreachable——网络不可达   ...

  6. BZOJ 1294 [SCOI2009]围豆豆Bean ——计算几何

    显然我们不可能表示出一台路径,因为实在是太复杂了. 所以我们可以记录一下路径对答案的影响,显然路径对答案影响相同的时候,答案更优,所以我们可以用影响来代替路径. 所以我们考虑状压一下所有的豆子有没有被 ...

  7. BZOJ 1086 [SCOI2005]王室联邦 ——DFS

    手把手教你树分块系列. 只需要记录一个栈,如果等于B的情况就弹栈,令省会为当前节点. 然后把待分块的序列不断上传即可. 考虑到有可能弹出不是自身节点的子树节点,所以记录一下当前的栈底. DFS即可 # ...

  8. [POJ1741]Tree(点分治模板)

    传送门 良心解析 其实以前在求某段序列上的区间统计问题时就碰到过类似于这样的思想. 当时的区间统计问题思路大致是这样: 选取一个点作为中间点,从这个点的左边和右边统计出满足条件的点对.然后当前的中间点 ...

  9. 【(好题)组合数+Lucas定理+公式递推(lowbit+滚动数组)+打表找规律】2017多校训练七 HDU 6129 Just do it

    http://acm.hdu.edu.cn/showproblem.php?pid=6129 [题意] 对于一个长度为n的序列a,我们可以计算b[i]=a1^a2^......^ai,这样得到序列b ...

  10. Java中NIO、BIO、AIO相关概念及应用场景

    1.同步阻塞IO(JAVA BIO):同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时,服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通 ...