1 创建日志文件夹
首先我们得把使用程序的人当成一个傻子,那就是用它不会给你自己建个目录来存日志,他希望的就是我点一下就可以了,再说了,日志我又不需要,仅仅是在程序遇到问题,需要调试排故的时候才可能用到,而且日志也不是越多越好吧。
所以我们这里的思路就是在程序启动的时候去打开数据库,在打开数据库之前,检查日志文件夹是否存在。如果不存在,那就给她建立一个日志文件夹,我的日志文件夹是log/年份,并且只保存本年的日志。代码如下
QDir* temp = new QDir;
if(!temp->exists("./log"))
if(!temp->mkdir("./log"))
QMessageBox::warning(nullptr,"警告","创建日志目录失败",QMessageBox::Ok);
QString mpath = "./log/" + QDateTime::currentDateTime().toString("yyyy");
if(!temp->exists(mpath))
if(!temp->mkdir(mpath))
QMessageBox::warning(nullptr,"警告","创建日志目录失败",QMessageBox::Ok);
if(deleteOld)
{
temp->setPath("./log");
temp->setFilter(QDir::Dirs);
QFileInfoList list = temp->entryInfoList();
int i = 0;
do{
QFileInfo fileInfo = list.at(i);
if((fileInfo.fileName() != ".") &&
(fileInfo.fileName() != "..") &&
(fileInfo.fileName() != QDateTime::currentDateTime().toString("yyyy")))
{
temp->setPath("./log/" + fileInfo.fileName());
temp->removeRecursively();
}
++i;
}while (i<list.size());
}
2 打开数据库
接着就是打开数据库了,我的想法是每一个月一个数据库文件,每一个数据库文件里面按照每一天建立一个表,这么存下来。代码如下
if(QSqlDatabase::contains("qt_sql_default_connection"))
g_DataBase = QSqlDatabase::database("qt_sql_default_connection");
else
{
mpath += ("/" + QDateTime::currentDateTime().toString("MM") + ".db");
g_DataBase = QSqlDatabase::addDatabase("QSQLITE");
g_DataBase.setDatabaseName(mpath);
g_DataBase.setUserName("Root");
g_DataBase.setPassword("Root");
if(!g_DataBase.open())
QMessageBox::warning(nullptr,"警告","数据库打开失败",QMessageBox::Ok);
else
{
QSqlQuery sql_query;
QString sqlString = QString("select count(*) from sqlite_master where type='table' and name='day%1'").arg(QDateTime::currentDateTime().toString("dd"));
sql_query.exec(sqlString);
if(sql_query.next())
{
if(sql_query.value(0).toUInt() == 0)
{
sqlString = QString("create table day%1 (id INTEGER PRIMARY KEY AUTOINCREMENT, threadID varchar(30), date varchar(30),level varchar(30), file varchar(300),line int, info varchar(300))").arg(QDateTime::currentDateTime().toString("dd"));
if(!sql_query.exec(sqlString))
QMessageBox::warning(nullptr,"警告","数据库建表失败",QMessageBox::Ok);
}
}
}
}
3 获取Qt输出消息
其实这部分网上有大量的代码,最主要的其实就是字符串分割。代码如下
void myLog(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QSqlQuery sql_query;
QString insert_sql = "insert into student values (?, ?, ?)";
QString temp,ThreadID,FileName,CurrentLine,Message;
temp = msg;
ThreadID = temp.mid(0,temp.indexOf("\r\n"));
temp = temp.mid(temp.indexOf("\r\n")+2);
FileName = temp.mid(0,temp.indexOf("\r\n"));
temp = temp.mid(temp.indexOf("\r\n")+2);
CurrentLine = temp.mid(0,temp.indexOf("\r\n"));
temp = temp.mid(temp.indexOf("\r\n")+2);
Message = temp.mid(0,temp.indexOf("\r\n"));
switch(type)
{
default:
break;
case QtDebugMsg:
{
insert_sql = QString("insert into day%1(threadID,date,level,file,line,info) values ('%2', '%3', '%4','%5','%6','%7')")
.arg(QDateTime::currentDateTime().toString("dd"))
.arg(ThreadID)
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg("Debug")
.arg(FileName)
.arg(CurrentLine)
.arg(Message);
sql_query.exec(insert_sql);
break;
}
case QtInfoMsg:
{
insert_sql = QString("insert into day%1(threadID,date,level,file,line,info) values ('%2', '%3', '%4','%5','%6','%7')")
.arg(QDateTime::currentDateTime().toString("dd"))
.arg(ThreadID)
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg("Info")
.arg(FileName)
.arg(CurrentLine)
.arg(Message);
sql_query.exec(insert_sql);
break;
}
case QtWarningMsg:
{
insert_sql = QString("insert into day%1(threadID,date,level,file,line,info) values ('%2', '%3', '%4','%5','%6','%7')")
.arg(QDateTime::currentDateTime().toString("dd"))
.arg(ThreadID)
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg("Warning")
.arg(FileName)
.arg(CurrentLine)
.arg(Message);
sql_query.exec(insert_sql);
break;
}
case QtCriticalMsg:
{
insert_sql = QString("insert into day%1(threadID,date,level,file,line,info) values ('%2', '%3', '%4','%5','%6','%7')")
.arg(QDateTime::currentDateTime().toString("dd"))
.arg(ThreadID)
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg("Critical")
.arg(FileName)
.arg(CurrentLine)
.arg(Message);
sql_query.exec(insert_sql);
break;
}
case QtFatalMsg:
{
insert_sql = QString("insert into day%1(threadID,date,level,file,line,info) values ('%2', '%3', '%4','%5','%6','%7')")
.arg(QDateTime::currentDateTime().toString("dd"))
.arg(ThreadID)
.arg(QDateTime::currentDateTime().toString("hh:mm:ss"))
.arg("Fatal")
.arg(FileName)
.arg(CurrentLine)
.arg(Message);
sql_query.exec(insert_sql);
break;
}
}
}
4 在主程序中劫持Qt消息
qInstallMessageHandler(myLog);
5 测试
首先在程序启动的时候会记录信息
qInfo()<< QThread::currentThreadId()<<"\r\n"<<__FILE__<<"\r\n"<<__LINE__<<"\r\n"<<"系统启动";
紧接着,我们在程序里面每10ms写入一条日志消息,如下
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QThread>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
timer = new QTimer;
connect(timer,&QTimer::timeout,this,[=](){
qDebug()<< QThread::currentThreadId()<<"\r\n"<<__FILE__<<"\r\n"<<__LINE__<<"\r\n"<<"我的大傻子";
});
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_logTest_clicked()
{
if(ui->pushButton_logTest->text() == "开始")
{
timer->start(10);
ui->pushButton_logTest->setText("停止");
}
else
{
timer->stop();
ui->pushButton_logTest->setText("开始");
}
}
程序启动,自动生成日志文件夹和日志文件
程序启动第一条日志写入数据库
模拟程序运行产生的日志,没10ms写入一条日志到数据库。
☞ 源码
源码链接:GitHub仓库自取
使用方法:☟☟☟