Qt编写调试日志输出类带网络转发(开源)
用qt开发商业程序已经九年了,陆陆续续开发过至少几十个程序,除了一些算不算项目的小工具外,大部分的程序都需要有个日志的输出功能,希望可以将程序的运行状态存储到文本文件或者数据库或者做其他处理等,qt对这个日志输出也做了很好的封装,在Qt4是qInstallMsgHandler,Qt5里边是qInstallMessageHandler,有了这个神器,只要在你的项目中所有qdebug qinfo等输出的日志信息,都会重定向接收到,网上大部分人写的demo都是接收到输出打印日志存储到文本文件,其实这就带给很多人误解,容易产生以为日志只能输出到文本文件,其实安装了日志钩子以后,拿到了所有调试打印信息,你完全可以用来存储到数据库+html有颜色区分格式的文件+网络转发输出(尤其适用于嵌入式linux**面程序,现场不方便外接调试打印的设备)。
做过的这么多项目中,Qt4和Qt5的都有,我一般保留四个版本,4.8.7,为了兼容qt4, 5.7.0,最后的支持XP的版本, 最新的长期支持版本5.9.7 最高的新版本5.12。毫无疑问,我要封装的这个日志类,也要支持4+5的,而且提供友好的接口。
1:支持动态启动和停止。
2:支持日志存储的目录。
3:支持网络发出打印日志。
4:支持Qt4+Qt5。开箱即用。
5:支持多线程。
6:使用做到最简单,start即可。
完整代码下载:https://download.csdn.net/download/feiyangqingyun/11010379
网络接收日志工具截图
完整代码:
#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 = );
~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 = );
~SendLog(); private:
static QScopedPointer<SendLog> self;
QTcpSocket *socket;
QTcpServer *server; private slots:
void newConnection(); public slots:
//发送日志
void send(const QString &content);
}; #endif // SAVELOG_H
#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()) {
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() - ).split(".").at();
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();
#else
qInstallMessageHandler();
#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()) {
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 = ;
#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();
}
}
Qt编写调试日志输出类带网络转发(开源)的更多相关文章
- Android开发调试日志工具类[支持保存到SD卡]
直接上代码: package com.example.callstatus; import java.io.File; import java.io.FileWriter; import java.i ...
- Qt编写图片及视频TCP/UDP网络传输
一.前言 很多年前就做过类似的项目,无非就是将本地的图片上传到服务器,就这么简单,其实用http的post上传比较简单容易,无需自定义协议,直接设置好二进制数据即可,而采用TCP或者UDP通信的话,必 ...
- Qt编写的开源帖子集合(懒人专用)
回顾自己学习Qt以来九年了,在这九年多时间里面,从本论坛学习不到不少的东西,今天特意整了一下自己开源过的资源的帖子,整理一起方便大家直接跳转下载,不统计不知道,一统计吓一跳,不知不觉开源了这么多代码, ...
- Qt编写自定义控件二动画按钮
现在的web发展越来越快,很多流行的布局样式,都是从web开始的,写惯了Qt widgets 项目,很多时候想改进一下现有的人机交互,尤其是在现有的按钮上加一些动画的效果,例如鼠标移上去变大,移开还原 ...
- Qt编写自定义控件大全
最新版可执行文件 http://pan.baidu.com/s/1i491FQP 不定期增加控件及修正BUG和改进算法. 总图: 1:动画按钮 * 1:可设置显示的图像和底部的文字 * 2:可设置普通 ...
- Qt编写自定义控件一开关按钮
从2010年进入互联网+智能手机时代以来,各种各样的APP大行其道,手机上面的APP有很多流行的元素,开关按钮个人非常喜欢,手机QQ.360卫士.金山毒霸等,都有很多开关控制一些操作,在Qt widg ...
- 使用spring框架进行aop编程实现方法调用前日志输出
aop编程 之使用spring框架实现方法调用前日志输出 使用spring框架实现AOP编程首先需要搭建spring框架环境: 使用Spring框架实现AOP工程编程之后,不需要我们去写代理工厂了,工 ...
- 日志输出--C#
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- Qt编写气体安全管理系统27-设备调试
一.前言 设备调试核心就是将整个系统中的所有打印数据统一显示到一个模块上,一般都会将硬件通信的收发数据和对应的解析信号发出来或者qdebug出来,这个在调试阶段非常有用,可以具体追踪问题出在哪,哪个数 ...
随机推荐
- wordpress模板修改及函数说明
原文:http://java-er.com/blog/wp-mb-edit/ WordPress基本模板文件 style.css : CSS(样式表)文件index.php : 主页模板archive ...
- 奇怪吸引子---Qi
奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...
- 解决微信小程序ios端滚动卡顿的问题
方案1:直接使用微信小程序提供的 “scroll-view " 组件. <scroll-view scroll-y style="height: 100%;"> ...
- 【网络】高性能网络编程--下一个10年,是时候考虑C10M并发问题了
转载:http://www.52im.net/thread-568-1-1.html 1.前言 在本系列文章的上篇中我们回顾了过云的10年里,高性能网络编程领域著名的C10K问题及其成功的解决方案(上 ...
- 未解决:长字符串含…
用reduce拼了一个超长sql语句,大约65000字符,运行通不过,报错: OperationalError: (1054, "Unknown column 'nan' in 'field ...
- Excel如何固定表头,任意一行
在日常Excel操作中,有时候内容比较多,需要将表头固定才能方便查看.那么,该如何固定表头呢?或者说如何固定任意一行我们制定的呢?下面以Excel2013进行详细的步骤讲解. 首先打开需要操作的Exc ...
- (原)MobileNetV1
转载请注明出处: https://www.cnblogs.com/darkknightzh/p/9410540.html 论文: MobileNets: Efficient Convolutional ...
- Gitbook 命令行工具
1.Gitbook 简介 1.1 Gitbook GitBook 是一个基于 Node.js 开发的命令行工具,使用它可以很方便的管理电子书,GitBook 是目前最流行的开源书籍写作方案. 使用 G ...
- ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
开发说测试环境在删除表的时候,报了如下错误: SQL> drop table tke purge; drop table tke purge * ERROR at line 1: ORA-000 ...
- Linux虚拟文件系统
从文件 I/O 看 Linux 的虚拟文件系统 1 引言 Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等.通过使用同一套文件 I/O 系统 调用即可对 Linux ...