文章来源:
小肖
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至405936398@qq.com举报,一经查实,本站将立刻删除。
Qt有两种实现记录日志的方式,第一种是安装自定义的Qt消息处理程序,自动输出程序产生的调试消息、警告、关键和致命错误消息的函数;第二种是自定义一个类,可以在程序指定位置打印输出指定的内容。
自定义消息处理函数,然后安装该函数,注意此时QDebug的消息将会输出在日志文件,Qt程序调式时不再打印。
在main.cpp文件中添加以下头文件和代码:
【领更多QT学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击→领取Qt开发进阶技术栈学习路线和资料
#include "mainwindow.h"#include <QApplication>#include <QDateTime>#include <QMutex>#include <QFile>#include <QTextStream>#include <QDebug>//#define LOG_FILE qApp->applicationDirPath()+"/logger.txt"void outputMessage(QtMsgType type, const QMessageLogContext &context, const QString &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:"); default: break; } QString context_info = QString("[%1 %2]:").arg(QString(context.function)).arg(context.line);//文件名,所在行数 QString current_date = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"); QString message = QString("%1 %2 %3").arg(current_date).arg(text).arg(msg);//.arg(context_info).arg(msg); QFile file("log.txt"); file.open(QIODevice::WriteOnly | QIODevice::Append); QTextStream text_stream(&file); text_stream << message << "\r\n"; file.flush(); file.close(); mutex.unlock();}int main(int argc, char *argv[]){ qInstallMessageHandler(outputMessage);//安装消息处理器调用回调函数 QApplication a(argc, argv); MainWindow w; w.show(); return a.exec();}
在mainwindow.cpp源文件中添加以下代码
#include "mainwindow.h"#include "ui_mainwindow.h"#include <QDebug>#define cout qDebug()<<"["<<__FUNCTION__<<":"<<__LINE__<<"]"#pragma execution_character_set("utf-8")MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow){ ui->setupUi(this); qDebug() << u8"这是一个写日志的测试"; // 调试信息提示 qWarning() << u8"这是一个写日志的测试"; // 一般的警告提示 qCritical() << u8"这是一个写日志的测试"; // 严重的错误提示 qFatal("qFatal %s", "这是一个写日志的测试"); // 致命错误不能用<<输出;}MainWindow::~MainWindow(){ delete ui;}
日志文件在项目里能看到:
日志内容:
【领更多QT学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
定义一个日志类,实现输出日志到指定文件的接口,在需要输出日志的地方调用接口即可。
clog.h
#ifndef CLOG_H#define CLOG_H#include <QFile>class CLog : public QObject{ Q_OBJECTpublic: /*! * @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 1024bool 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