Qt+QtWebApp开发笔记(二):http服务器日志系统介绍、添加日志系统至Demo测试

article/2025/10/2 6:09:35

若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/130762721

红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…

Qt开发专栏:三方库开发技术

上一篇:《Qt+QtWebApp开发笔记(一):QtWebApp介绍、下载和搭建基础封装http轻量级服务器Demo》
下一篇:《Qt+QtWebApp开发笔记(三):http服务器动态html连接跳转基础交互》


前言

  上一篇使用QtWebApp的基于Qt的轻量级http服务器实现了一个静态网页返回的Demo,网页服务器很重要的就是日志,因为在服务器类上并没有直接返回,所以,本篇先把日志加上。


Demo

  在这里插入图片描述

下载地址

  链接:https://pan.baidu.com/s/1BPVRLS07qk-WPi-txERKbg?pwd=1234


日志系统

生产环境需要查看旧的日志消息,例如两天前的日志消息。

  可以简单地将输出重定向到一个文件(MyFirstWebApp>logfile.txt),但这有两个问题:

  • 在许多系统上,输出重定向有些慢。
  • 日志文件将变得无限大,如果不短时间停止web服务器,就无法防止这种情况发生。

  因此,最好让web服务器自己将所有消息写入文件。这就是记录器模块的作用。
  要将日志模块的源代码包括到项目中,请在项目文件中添加一行:

include(../QtWebApp/QtWebApp/logging/logging.pri)

  这个而模块也是QtWebApp的logging模块,如下:
  在这里插入图片描述
  然后在程序的*.ini文件中添加另一个部分:

[logging]
minLevel=WARNING
bufferSize=100
fileName=../logs/webapp1.log
maxSize=1000000
maxBackups=2
timestampFormat=dd.MM.yyyy hh:mm:ss.zzz
msgFormat={timestamp} {typeNr} {type} {thread} {msg}

  日志级别有:DEBUG(别名ALL)、INFO、WARN或WARNING、CRITICAL(别名ERROR)、FATAL。信息级别由Qt 5.5引入。
  上面的示例配置启用线程本地缓冲区,**这些缓冲区将不太重要的消息保留在内存中,直到出现警告或严重错误。**然后,错误消息与收集到的低级消息一起写入日志文件。只要一切正常,使用缓冲区可以大大减少日志文件的大小。像这样的系统操作员。
  但是,缓冲区的内存和性能成本都很高。收益通常大于成本。要禁用缓冲区,请将bufferSize设置为0。在这种情况下,只有配置了minLevel及以上级别的消息才会写入日志文件。
  如果没有指定文件名,则记录器会写入控制台。日志文件的路径可以是绝对路径,也可以是相对于配置文件的文件夹的路径。maxSize参数限制日志文件的大小(以字节为单位)。当超过此限制时,记录器将启动一个新文件。设置maxBackups指定磁盘上应保留多少旧日志文件。
  时间戳格式设置的作用。QDateTime::toString()的文档以获得对字符的解释,还有更多可用的内容。msgFormat设置指定每条消息的格式。以下字段可用:

  • {timestamp}:创建日期和时间
  • {typeNr}:数字格式的消息类型或级别(0=DEBUG, 4=INFO, 1=WARNING, 2=CRITICAL, 3=FATAL)
  • {type}:字符串格式的消息类型或级别(DEBUG, INFO, WARNING, CRITICAL, FATAL)
  • {thread}:线程的ID号
  • {msg}:消息文本
  • {xxx}:可以自己定义的任何记录器变量QT 5.0及更新版本在调试模式下有一些附加变量:
{file}:Filename of source code where the message was generated
{function}:Function where the message was generated
{line}:Line number where the message was generated

  Qt开发人员将这三个字段添加到他们的框架中。也可以使用\n在消息格式中插入换行符和插入  制表符。上述所有变量也可以在日志消息中使用,例如:

qCritical("An error occured in {file}: out of disk space");

  需要一个指向FileLogger实例的全局指针,以便整个程序都可以访问它。首先添加到global.h:

#include "httpsessionstore.h"
#include "staticfilecontroller.h"
#include "templatecache.h"
#include "filelogger.h"using namespace stefanfrings;/** Storage for session cookies */
extern HttpSessionStore* sessionStore;/** Controller for static files */
extern StaticFileController* staticFileController;/** Cache for template files */
extern TemplateCache* templateCache;/** Redirects log messages to a file */
extern FileLogger* logger;#endif // GLOBAL_H

  global.cpp:

#include "global.h"HttpSessionStore* sessionStore;
StaticFileController* staticFileController;
TemplateCache* templateCache;
FileLogger* logger;

  在main.cpp中,配置FileLogger的实例:

int main(int argc, char *argv[])
{QCoreApplication app(argc, argv);QString configFileName=searchConfigFile();// Configure loggingQSettings* logSettings=new QSettings(configFileName,QSettings::IniFormat,&app);logSettings->beginGroup("logging");logger=new FileLogger(logSettings,10000,&app);logger->installMsgHandler();// Log the library versionqDebug("QtWebApp has version %s",getQtWebAppLibVersion());// Session storeQSettings* sessionSettings=new QSettings(configFileName,QSettings::IniFormat,&app);sessionSettings->beginGroup("sessions");sessionStore=new HttpSessionStore(sessionSettings,&app);// Static file controllerQSettings* fileSettings=new QSettings(configFileName,QSettings::IniFormat,&app);fileSettings->beginGroup("files");staticFileController=new StaticFileController(fileSettings,&app);// Configure template cacheQSettings* templateSettings=new QSettings(configFileName,QSettings::IniFormat,&app);templateSettings->beginGroup("templates");templateCache=new TemplateCache(templateSettings,&app);// HTTP serverQSettings* listenerSettings=new QSettings(configFileName,QSettings::IniFormat,&app);listenerSettings->beginGroup("listener");new HttpListener(listenerSettings,new RequestMapper(&app),&app);return app.exec();
}

  数字10000是以毫秒为单位的刷新间隔,记录器使用它来重新加载配置文件。因此,可以在程序运行时编辑任何记录器设置,并且更改在几秒钟后生效,而无需重新启动服务器。如果不希望自动重新加载,请使用值0。
  给了一个示例代码,用于查询和记录库的版本号。一些人要求添加该功能。
不要忘记创建一个空文件夹MyFirstWebApp/logs。记录器本身不会创建文件夹。
  现在可以启动应用程序并查看会发生什么。因为程序没有错误,所以日志文件保持为空。但  可以看到控制台窗口中的输出已降至最低:
  在这里插入图片描述

  让在logincontroller.cpp中插入一条qCritical()消息,然后可以看到日志缓冲区工作:
  然后打开URLhttp://localhost:8080/login?username=test&password=wrong.
  再次查看日志文件,它就在那里:
  在这里插入图片描述

  现在通过将min Level降低到DEBUG来进行另一个测试。保存ini文件,等待10秒,然后打开URLhttp://localhost:8080/hello.再次检查日志文件。可以看到,尽管没有发生错误,但现在所有的调试消息都已写入。因此,在不重新启动程序的情况下更改日志级别可以很好地工作。
  在这里插入图片描述

  其实这个很容易看出来,是直接对qt的几个日志等级进行了(PS:这个日志库还不错,installMsgHandler可以截断qDebug等相关的错误信息,可以直接无缝使用到每一个qt项目中,有这个兴趣可以试一试)。
  在这里插入图片描述


记录器变量

  写到记录器支持用户定义的变量。这些变量是线程本地的,在清除它们之前一直保留在内存中。对于web应用程序,在每条消息中记录当前用户的名称可能很有用。向requestmapper.cpp添加代码以设置记录器变量:

void RequestMapper::service(HttpRequest& request, HttpResponse& response) {QByteArray path=request.getPath();qDebug("RequestMapper: path=%s",path.data());HttpSession session=sessionStore->getSession(request,response,false);QString username=session.get("username").toString();logger->set("currentUser",username);...
}

  通过这种方式,请求映射器在将请求传递给控制器类之前,为所有传入的HTTP请求查询调用用户的名称。
  现在可以修改ini文件以使用该变量:

msgFormat={timestamp} {typeNr} {type} {thread} User:{currentUser} {msg}

  运行程序并打开URLhttp://localhost:8080/login?username=test&password=hello两次。然后再次检查日志文件:
  在这里插入图片描述

  在用户登录之前,可以看到变量{currentUser}为空。然后,所有以下请求都会以该用户的名称记录。
  注意:在RequestMapper类中放置了许多静态资源(logger、sessionStore、staticFileController、templateCache)。在实际应用程序中,建议创建一个单独的类,例如名称为“Globals”的类,这样每个人都知道在哪里可以找到这样的资源。或者按照在Demo1项目中的例子,将它们放在任何类之外的cpp源文件中。

日志缓冲区和线程池

  由于线程被重新用于后续的HTTP请求,记录器可能会输出更多的细节。例如,假设第一个成功的HTTP请求会产生一些隐藏的调试消息,然后由同一线程处理的第二个请求会产生错误。然后,日志文件将包含错误消息以及所有缓冲的调试消息。但其中一些来自以前的HTTP请求,并不需要它。
  要清除两个HTTP请求之间的缓冲区,请添加到requestmapper.cpp:

void RequestMapper::service(HttpRequest& request, HttpResponse& response) {...else {response.setStatus(404,"Not found");response.write("The URL is wrong, no such document.");}qDebug("RequestMapper: finished request");logger->clear(true,true);
}

  因此,每当HTTP请求的处理完成时,都要清理记录器的内存。当同一个线程处理下一个请求时,它将以空缓冲区开始。(碰到错误则会输出到文件,所以一个http请求完成了,就是其前面的日志都是无错误,所以可以清空了)。

双文件记录器

  该项目还包含一个DualFileLogger类,可用于并行生成两个日志文件。这可能对以下设置组合有用:

  • 主记录日志文件
minLevel=INFO
bufferSize=0
  • 第二日志文件
minLevel=ERROR (or WARNING)
bufferSize=100

  这样,主日志文件就不包含调试消息。但是,当发生错误时,辅助日志文件会包含该错误以及多达100条相关的调试消息。如果错误消息本身无法识别问题原因,则此文件特别有用。

总结

  这个日志logging模块起到的最大作用,是因为在QtWebApp三方源码中的qDebug,qWarn,QFatal等相关系统直接输出到控制台的,使用该日志则截断才可以获取httpservice模块以及其他模块中的打印调试信息,而这些信息是在函数返回值中没有体现的。
  为了能查看到三方模块日志,则必须要使用logging模块,或者自己写一个模块去截断,或者直接修改三方源码中的调试信息的代码。
  使用httpservice肯定是最好使用logging模块了。


Demo增量:添加logging日志模块

步骤一:准备代码模板

  准备之前的demo模板:
  在这里插入图片描述

步骤二:拷贝logging模块

  将QtWebApp中的logging,符合模块化设计准则,如下图:
  在这里插入图片描述

  拷贝到的Demo
  在这里插入图片描述

  添加模块进入工程:

# logging模块,QtWebApp自带的三方模块
include ($$PWD/modules/logging/logging.pri)

  在这里插入图片描述
  第三方的模块。

步骤三:添加配置logging的配置文件

  先把上一篇的Demo配置文件加了listener之后就读不出的问题解决了,其实区别关键在下面:
  在这里插入图片描述

  beginGroup就是进入了这一组,这一组拿到key就可以不带前缀。
  在这里插入图片描述

  然后开始添加日志配置,也在httpServerManager,因为配置文件beginGroup之后就是操作单独一组了,这里从第三方源码中也可以看出来:
  在这里插入图片描述

  本次加入logging,也要进行配置文件分组的区分,原来的_pSettings改成_pHttpListenerSettings,然后新增_pLoggingListenerSettings用于配置logging模块的配置实例:

步骤四:新增logging日志代码

  在这里插入图片描述

  在这里插入图片描述

  在这里插入图片描述

步骤五:运行结果

   在这里插入图片描述
  至此,日志加入成功

步骤六:日志配置调整

  在这里插入图片描述

  修改下日志时间:
  在这里插入图片描述

  记录日志则是:
  在这里插入图片描述


Demo源码

HttpServerManager.h

#ifndef HTTPSERVERMANAGER_H
#define HTTPSERVERMANAGER_H#include <QObject>
#include <QMutex>#include "httplistener.h"
#include "filelogger.h"#include "HelloWorldRequestHandler.h"class HttpServerManager : public QObject
{Q_OBJECT
private:explicit HttpServerManager(QObject *parent = 0);public:static HttpServerManager *getInstance();public slots:void slot_start();                              // 开启线程void slot_stop();                               // 停止线程private:static HttpServerManager *_pInstance;static QMutex _mutex;private:bool _running;                                  // 运行状态private:HttpListener *_pHttpListener;                   // http服务监听器QSettings *_pHttpListenerSettings;              // http服务器配置文件FileLogger *_pFileLogger;                       // 日志记录QSettings *_pFileLoggerSettings;                // 日志配置文件private:QString _ip;                // 服务器监听ip(若为空,则表示监听所有ip)quint16 _port;              // 服务器监听端口int _minThreads;            // 空闲最小线程数int _maxThreads;            // 负载最大线程数int _cleanupInterval;       // 空线程清空间隔(单位:毫秒)int _readTimeout;           // 保持连接空载超时时间(单位:毫秒)int _maxRequestSize;        // 最大请求数int _maxMultiPartSize;      // 上载文件最大数(单位:字节)
};#endif // HTTPSERVERMANAGER_H

HttpServerManager.cpp

#include "HttpServerManager.h"
#include <QApplication>#include <QDir>#include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz")HttpServerManager *HttpServerManager::_pInstance = 0;
QMutex HttpServerManager::_mutex;HttpServerManager::HttpServerManager(QObject *parent): QObject(parent),_pHttpListener(0),_pHttpListenerSettings(0),_pFileLogger(0),_pFileLoggerSettings(0),_running(false),_port(8088),_minThreads(2),_maxThreads(10),_cleanupInterval(60000),_readTimeout(60000),_maxRequestSize(100),_maxMultiPartSize(1024*1024*1024)
{}HttpServerManager *HttpServerManager::getInstance()
{if(!_pInstance){QMutexLocker lock(&_mutex);if(!_pInstance){_pInstance = new HttpServerManager();}}return _pInstance;
}void HttpServerManager::slot_start()
{if(_running){LOG << "It's running!!!";return;}_running = true;LOG << "Succeed to run";QString httpServerPath = QString("%1/etc/httpServer.ini").arg(qApp->applicationDirPath());LOG << httpServerPath << "exit:" << QFile::exists(httpServerPath);// 启动日志几里路{if(!_pFileLoggerSettings){_pFileLoggerSettings = new QSettings(httpServerPath, QSettings::IniFormat);}_pFileLoggerSettings->beginGroup("logging");// 日志不会主动创建文件夹,这里需要补全{QFileInfo fileInfo(httpServerPath);QString dirPath = fileInfo.dir().absolutePath();dirPath = QString("%1/%2").arg(dirPath).arg(_pFileLoggerSettings->value("fileName").toString());dirPath = dirPath.mid(0, dirPath.lastIndexOf("/"));QDir dir;dir.mkpath(dirPath);}_pFileLogger = new FileLogger(_pFileLoggerSettings);_pFileLogger->installMsgHandler();}// 启动http的监听{if(!_pHttpListenerSettings){_pHttpListenerSettings = new QSettings(httpServerPath, QSettings::IniFormat);}_pHttpListenerSettings->beginGroup("listener");_pHttpListener = new HttpListener(_pHttpListenerSettings, new HelloWorldRequestHandler);}LOG;
}void HttpServerManager::slot_stop()
{if(!_running){LOG <<"It's not running!!!";return;}_running = false;LOG << "Succeed to stop";
}

工程模板v1.1.0

  在这里插入图片描述


入坑

入坑一:日志一直不出来

问题

  日志一直不出来

原因

  在这里插入图片描述

  日志log文件的路径是基于ini配置文件的相对路径

解决

  在这里插入图片描述


上一篇:《Qt+QtWebApp开发笔记(一):QtWebApp介绍、下载和搭建基础封装http轻量级服务器Demo》
下一篇:《Qt+QtWebApp开发笔记(三):http服务器动态html连接跳转基础交互》


若该文为原创文章,转载请注明原文出处
本文章博客地址:https://hpzwl.blog.csdn.net/article/details/130762721


http://chatgpt.dhexx.cn/article/YvG4s0jV.shtml

相关文章

WebApp开发----数字角标

数字角标--有底色和无底色 数字角标一般和其它控件&#xff08;列表、9宫格、选项卡等&#xff09;配合使用&#xff0c;用于进行数量提示。 角标的核心类是.mui-badge&#xff0c;默认为实心灰色背景&#xff1b;同时&#xff0c;mui还内置了蓝色&#xff08;blue&#xff09…

WebApp开发学习

1.折叠面板 <!DOCTYPE html> <html> <head><meta charset"utf-8"><meta name"viewport" content"widthdevice-width,initial-scale1,minimum-scale1,maximum-scale1,user-scalableno" /><title></title…

webApp开发心得

从事单页相关的开发一年有余&#xff0c;期间无比的推崇webapp的网站模式&#xff0c;也整理了很多移动开发的知识点&#xff0c;但是现在回过头来看&#xff0c;webapp究竟是好还是不好真是一言难尽哟&#xff01; webapp使用JavaScript修改页面&#xff1b;紧接着再从服务器…

Qt+QtWebApp开发笔记(一):QtWebApp介绍、下载和搭建基础封装http轻量级服务器Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/130631547 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

安卓WebApp开发-项目MiliSetu

文章目录 目录 文章目录 前言 WebAPP开发 一、WebAPP是什么&#xff1f; 二、安装HBuilder X 1.HBuilder X 官网 2.创建一个app项目 3.项目文件 ​编辑 index 总结 前言 WebAPP开发 WebApp开发&#xff0c;是移动端程序的实现方式之一&#xff0c;是一种简单&#…

关于webapp开发

最近想搞一个自用的手机app&#xff0c;但是Android开发给我的感觉是麻烦&#xff0c;想着web也可以制作手机app&#xff0c;于是去网上搜索了一番&#xff0c;最后下载了HBuilderX&#xff0c;然后开始搞&#xff0c;对于原生web&#xff0c;选择5App&#xff0c;默认模板就行…

Web App 开发

0. jQuery Mobile 介绍 jQM是为触控优化的移动web框架&#xff0c;用来设计响应式网站和跨平台移动开发的&#xff1b; &#xff08;这里的跨平台指的是可以运行在iOS、Android、BlackBerry、WindowsPhone各种平台上&#xff09; jQM的资料多而且详细、容易上手&#xff0c;对…

【WebApp】webApp开发总结(集合转贴)

为什么80%的码农都做不了架构师&#xff1f;>>> 【来源地址】 http://www.cnblogs.com/pifoo/archive/2011/05/28/webkit-webapp.htmlhttp://classjs.com/tag/%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%BC%80%E5%8F%91/http://java-mans.iteye.com/blog/1639503http://www.z…

iOS开发入门——项目创建

iOS开发入门——项目创建 1、新建项目 2、项目模版 3、项目配置 配置好之后点下一步就好。。。。 4、确定存储位置 5、启动模拟器 这就是第一个空白项目的创建过程&#xff0c;后面将持续更新iOS开发学习经历。

ios开发基础教程

博客专栏 斯坦福iOS公开课笔记 文章&#xff1a;8篇 阅读&#xff1a;11187 IOS开发进阶 文章&#xff1a;9篇 阅读&#xff1a;34499 深入浅出Objective-C 文章&#xff1a;17篇 阅读&#xff1a;56719 IOS开发入门实例 文章&#xff1a;30篇 阅读&#xff1a;134894

iOS开发学习指南

1. 提升你的英语水平 虽然知乎er的平均水平比较高&#xff0c;但是现实情况是很大一部分程序员的英文水平是不太过关的。那大概需要提升到什么水平呢&#xff1f;我觉得达到比较流畅的阅读技术文档及书籍&#xff0c;配合英文字幕可以比较轻松的观看wwdc的session的水平就可以…

iOS开发入门——简单上手体验

iOS开发入门——简单上手体验 下面我们正式进入对iOS即swift的探索了解&#xff0c;我们在上一篇iOS开发入门——项目创建中已经创建了一个项目&#xff0c;我们将基于它继续探索&#xff0c;如下图所示&#xff1a; 我们双击即可进入这个项目。 1、进入项目 进入项目后如下图…

IOS开发之——入门

前言 目前主要的移动开发平台有&#xff1a;Android、iOS、WindowsPhone&#xff0c;前两者占据着绝大多数的终端应用&#xff0c;我们常说的移动开发就是指&#xff1a;Android和iOS开发。本位主要讲述IOS的开发。 Android、iOS系统架构对比 android是基于Linux内核设计的&…

ios开发学习

记录一下ios开发遇到好网站 http://www.cnblogs.com/kenshincui/p/3985090.html Kenshin Cuis Blog CODING 完美世界... iOS开发系列文章&#xff08;持续更新……&#xff09; 2014-09-21 22:17 by KenshinCui, 43498 阅读, 50 评论, 收藏, 编辑 iOS开发系列的文章&#xf…

iphone开发教程(1) iOS大纲

iOS 大纲 iOS 由操作系统和应用技术构成。虽然和 Mac OS X 共用了很多技术&#xff0c;但是 iOS 是专门为了移动设备而设计的。当然如果你以前做过 Mac OS X 的应用程序&#xff0c;你会发现很多相似之处&#xff0c;但是很多技术只能在 iOS 里面使用&#xff0c;比如支持多…

ios app开发学习流程(入门到精通)

一、xcode编译并运行app后&#xff0c;iphone模拟器已安装的app所在目录&#xff1a; &#xff03; 1. /Users/alpha/Library/Application Support/iPhone Simulator/5.1/Applications &#xff03; 2. 删除此目录下的app目录&#xff0c;即可清空模拟器里安装过的app &#xf…

iOS开发系列课程(01) --- iOS编程入门

iOS概述 什么是iOS iOS是苹果公司为它的移动设备&#xff08;iPhone、iPad、iWatch等&#xff09;开发的移动操作系统。 iOS发展史 2007年苹果发布iPhone Runs OS X2008年更名iPhone OS2010年更名iOS2012年WWCD 2012上发布iOS 62013年WWCD 2013上发布iOS 72014年WWCD 2014上…

iOS苹果开发者账号申请教程

只有苹果开发者账号才能上架App Store&#xff0c;苹果开发者需要年费&#xff0c;是苹果公司收的&#xff01; 开发者账号类型功能介绍 下面是个人苹果开发者申请步骤流程&#xff1a; 分五个步骤进行 1、注册苹果账号apple id 2、开启双重认证 3、下载Apple Developer应…

零基础如何学习 iOS 开发?

作为一名混迹iOS开发圈近4年的码农&#xff0c;资历不深不浅&#xff0c;看到这个问题还是忍不住想回答一下。 如果你打算学习iOS开发&#xff0c;那么在开始学之前&#xff0c;你要做好以下4个方面的准备。 ————————————————————— 1 、信念。 很大程…

【原创】iOS开发入门教程

2019独角兽企业重金招聘Python工程师标准>>> 程序发轻狂&#xff0c;代码阑珊&#xff0c;苹果开发安卓狂&#xff01;——写给狂热的编程爱好者们 ###写在前面的话 学习iOS应用程序开发已有一段时间&#xff0c;最近稍微闲下来了&#xff0c;正好也想记录一下前阶段…