新增日志重定向和运行时间记录

This commit is contained in:
feiyangqingyun
2019-10-14 10:24:47 +08:00
parent 6cb47c6db3
commit 534c165c16
16 changed files with 908 additions and 122 deletions

65
savelog/frmsavelog.cpp Normal file
View File

@@ -0,0 +1,65 @@
#pragma execution_character_set("utf-8")
#include "frmsavelog.h"
#include "ui_frmsavelog.h"
#include "savelog.h"
#include "qdatetime.h"
#include "qtimer.h"
#include "qdebug.h"
frmSaveLog::frmSaveLog(QWidget *parent) : QWidget(parent), ui(new Ui::frmSaveLog)
{
ui->setupUi(this);
this->initForm();
}
frmSaveLog::~frmSaveLog()
{
delete ui;
}
void frmSaveLog::initForm()
{
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(append()));
timer->setInterval(1000);
SaveLog::Instance()->setPath(qApp->applicationDirPath());
}
void frmSaveLog::append()
{
QString msg = QString("当前时间: %1 测试打印输出消息").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"));
ui->txtMain->append(msg);
qDebug() << msg;
}
void frmSaveLog::on_btnDebug_clicked()
{
QString msg = QString("当前时间: %1 手动插入消息").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss"));
ui->txtMain->append(msg);
qDebug() << msg;
}
void frmSaveLog::on_ckTimer_stateChanged(int arg1)
{
if (arg1 == 0) {
timer->stop();
} else {
timer->start();
}
}
void frmSaveLog::on_ckNet_stateChanged(int arg1)
{
SaveLog::Instance()->setToNet(arg1 != 0);
}
void frmSaveLog::on_ckSave_stateChanged(int arg1)
{
if (arg1 == 0) {
SaveLog::Instance()->stop();
} else {
SaveLog::Instance()->start();
}
}

32
savelog/frmsavelog.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef FRMSAVELOG_H
#define FRMSAVELOG_H
#include <QWidget>
namespace Ui {
class frmSaveLog;
}
class frmSaveLog : public QWidget
{
Q_OBJECT
public:
explicit frmSaveLog(QWidget *parent = 0);
~frmSaveLog();
private:
Ui::frmSaveLog *ui;
QTimer *timer;
private slots:
void initForm();
void append();
void on_btnDebug_clicked();
void on_ckTimer_stateChanged(int arg1);
void on_ckNet_stateChanged(int arg1);
void on_ckSave_stateChanged(int arg1);
};
#endif // FRMSAVELOG_H

58
savelog/frmsavelog.ui Normal file
View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>frmSaveLog</class>
<widget class="QWidget" name="frmSaveLog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QCheckBox" name="ckTimer">
<property name="text">
<string>定时器打印消息</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QCheckBox" name="ckSave">
<property name="text">
<string>保存日志</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="btnDebug">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>手动插入消息</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QTextEdit" name="txtMain"/>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="ckNet">
<property name="text">
<string>重定向到网络</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

31
savelog/main.cpp Normal file
View File

@@ -0,0 +1,31 @@
#pragma execution_character_set("utf-8")
#include "frmsavelog.h"
#include <QApplication>
#include <QTextCodec>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setFont(QFont("Microsoft Yahei", 9));
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
#if _MSC_VER
QTextCodec *codec = QTextCodec::codecForName("gbk");
#else
QTextCodec *codec = QTextCodec::codecForName("utf-8");
#endif
QTextCodec::setCodecForLocale(codec);
QTextCodec::setCodecForCStrings(codec);
QTextCodec::setCodecForTr(codec);
#else
QTextCodec *codec = QTextCodec::codecForName("utf-8");
QTextCodec::setCodecForLocale(codec);
#endif
frmSaveLog w;
w.setWindowTitle("输出日志文件");
w.show();
return a.exec();
}

193
savelog/savelog.cpp Normal file
View File

@@ -0,0 +1,193 @@
#include "savelog.h"
#include "qmutex.h"
#include "qfile.h"
#include "qtcpsocket.h"
#include "qtcpserver.h"
#include "qdatetime.h"
#include "qapplication.h"
#include "qtimer.h"
#include "qstringlist.h"
#define QDATE qPrintable(QDate::currentDate().toString("yyyy-MM-dd"))
//日志重定向
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
void Log(QtMsgType type, const char *msg)
#else
void Log(QtMsgType type, const QMessageLogContext &, const QString &msg)
#endif
{
//加锁,防止多线程中qdebug太频繁导致崩溃
QMutex mutex;
QMutexLocker locker(&mutex);
QString content;
//这里可以根据不同的类型加上不同的头部用于区分
switch (type) {
case QtDebugMsg:
content = QString("%1").arg(msg);
break;
case QtWarningMsg:
content = QString("%1").arg(msg);
break;
case QtCriticalMsg:
content = QString("%1").arg(msg);
break;
case QtFatalMsg:
content = QString("%1").arg(msg);
break;
}
SaveLog::Instance()->save(content);
}
QScopedPointer<SaveLog> SaveLog::self;
SaveLog *SaveLog::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new SaveLog);
}
}
return self.data();
}
SaveLog::SaveLog(QObject *parent) : QObject(parent)
{
//必须用信号槽形式,不然提示 QSocketNotifier: Socket notifiers cannot be enabled or disabled from another thread
//估计日志钩子可能单独开了线程
connect(this, SIGNAL(send(QString)), SendLog::Instance(), SLOT(send(QString)));
file = new QFile(this);
toNet = false;
//默认取应用程序根目录
path = qApp->applicationDirPath();
//默认取应用程序可执行文件名称
QString str = qApp->applicationFilePath();
QStringList list = str.split("/");
name = list.at(list.count() - 1).split(".").at(0);
fileName = "";
}
SaveLog::~SaveLog()
{
file->close();
}
//安装日志钩子,输出调试信息到文件,便于调试
void SaveLog::start()
{
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
qInstallMsgHandler(Log);
#else
qInstallMessageHandler(Log);
#endif
}
//卸载日志钩子
void SaveLog::stop()
{
#if (QT_VERSION <= QT_VERSION_CHECK(5,0,0))
qInstallMsgHandler(0);
#else
qInstallMessageHandler(0);
#endif
}
void SaveLog::save(const QString &content)
{
//如果重定向输出到网络则通过网络发出去,否则输出到日志文件
if (toNet) {
emit send(content);
} else {
//方法改进:之前每次输出日志都打开文件,改成只有当日期改变时才新建和打开文件
QString fileName = QString("%1/%2_log_%3.txt").arg(path).arg(name).arg(QDATE);
if (this->fileName != fileName) {
this->fileName = fileName;
if (file->isOpen()) {
file->close();
}
file->setFileName(fileName);
file->open(QIODevice::WriteOnly | QIODevice::Append | QFile::Text);
}
QTextStream logStream(file);
logStream << content << "\n";
}
}
void SaveLog::setToNet(bool toNet)
{
this->toNet = toNet;
}
void SaveLog::setPath(const QString &path)
{
this->path = path;
}
void SaveLog::setName(const QString &name)
{
this->name = name;
}
//网络发送日志数据类
QScopedPointer<SendLog> SendLog::self;
SendLog *SendLog::Instance()
{
if (self.isNull()) {
static QMutex mutex;
QMutexLocker locker(&mutex);
if (self.isNull()) {
self.reset(new SendLog);
}
}
return self.data();
}
SendLog::SendLog(QObject *parent)
{
socket = NULL;
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
int listenPort = 6000;
#if (QT_VERSION > QT_VERSION_CHECK(5,0,0))
server->listen(QHostAddress::AnyIPv4, listenPort);
#else
server->listen(QHostAddress::Any, listenPort);
#endif
}
SendLog::~SendLog()
{
if (socket != NULL) {
socket->disconnectFromHost();
}
server->close();
}
void SendLog::newConnection()
{
while (server->hasPendingConnections()) {
socket = server->nextPendingConnection();
}
}
void SendLog::send(const QString &content)
{
if (socket != NULL && socket->isOpen()) {
socket->write(content.toUtf8());
socket->flush();
}
}

84
savelog/savelog.h Normal file
View File

@@ -0,0 +1,84 @@
#ifndef SAVELOG_H
#define SAVELOG_H
#include <QObject>
class QFile;
class QTcpSocket;
class QTcpServer;
#ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif
class QDESIGNER_WIDGET_EXPORT SaveLog : public QObject
#else
class SaveLog : public QObject
#endif
{
Q_OBJECT
public:
static SaveLog *Instance();
explicit SaveLog(QObject *parent = 0);
~SaveLog();
private:
static QScopedPointer<SaveLog> self;
//文件对象
QFile *file;
//是否重定向到网络
bool toNet;
//日志文件路径
QString path;
//日志文件名称
QString name;
//日志文件完整名称
QString fileName;
signals:
void send(const QString &content);
public slots:
//启动日志服务
void start();
//暂停日志服务
void stop();
//保存日志
void save(const QString &content);
//设置是否重定向到网络
void setToNet(bool toNet);
//设置日志文件存放路径
void setPath(const QString &path);
//设置日志文件名称
void setName(const QString &name);
};
class SendLog : public QObject
{
Q_OBJECT
public:
static SendLog *Instance();
explicit SendLog(QObject *parent = 0);
~SendLog();
private:
static QScopedPointer<SendLog> self;
QTcpSocket *socket;
QTcpServer *server;
private slots:
void newConnection();
public slots:
//发送日志
void send(const QString &content);
};
#endif // SAVELOG_H

23
savelog/savelog.pro Normal file
View File

@@ -0,0 +1,23 @@
#-------------------------------------------------
#
# Project created by QtCreator 2019-02-16T15:08:47
#
#-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = savelog
TEMPLATE = app
DESTDIR = $$PWD/../bin
CONFIG += warn_off
SOURCES += main.cpp
SOURCES += frmsavelog.cpp
SOURCES += savelog.cpp
HEADERS += frmsavelog.h
HEADERS += savelog.h
FORMS += frmsavelog.ui