当前位置: 首页 > article >正文

Flask实现高效日志记录模块

目录

一. 简介:

1. 为什么需要请求日志

二.  日志模块组成

1.  对应日志表创建(包含日志记录的关键字段)

2.  编写日志记录静态方法

3.  在Flask中捕获请求日志

4.  捕获异常并记录错误日志

5.  编写日志接口数据展示

6.  写入数据展示

三. 日志信息格式处理问题

1. 如何处理流式响应(Passthrough)

2. 如何记录响应数据(如JSON响应)

3. 总结与优化建议

四 . 结尾


一. 简介:

在Flask应用中,日志记录是重要的功能之一,它可以帮助开发人员跟踪请求的处理情况,快速定位错误,并且有助于应用的监控与调试。本文将介绍如何在Flask应用中实现请求日志记录,包括如何记录请求的各种信息(如请求数据、响应数据、错误信息等)并将其保存到数据库中。我们还会演示如何捕获不同级别的日志(信息级别、错误级别),并讨论如何处理复杂的响应数据(如流式响应)。


1. 为什么需要请求日志

日志记录可以帮助开发人员和运维团队了解应用的行为和状态,尤其是在生产环境中。通过记录每次请求的详细信息,开发人员能够:

  • 跟踪应用性能。
  • 快速定位和调试错误。
  • 为监控和安全审计提供数据支持。

例如,在出现错误时,记录详细的堆栈信息、请求的URL、请求参数和响应数据,能够帮助你迅速分析问题并进行修复。

二.  日志模块组成

  1.  对应日志表创建(包含日志记录的关键字段

# 日志表
class Log(db.Model,TimestampMixin):"""日志表"""__tablename__ = 't_logs'__table_args__ = {'mysql_engine': 'InnoDB','comment': '日志表'}id = db.Column(db.Integer, primary_key=True, autoincrement=True,comment='id')user_id = db.Column(db.Integer,comment='用户ID')  # 用户IDip_address = db.Column(db.String(50),comment='ip地址')  # ip地址level = db.Column(db.String(50),comment='日志级别')  # 日志级别message = db.Column(db.Text,comment='日志内容')  # 日志内容module = db.Column(db.String(100),comment='模块名称')  # 模块名称method = db.Column(db.String(50),comment='方法名称')  # 方法名称url = db.Column(db.String(255),comment='请求的URL')  # 请求的URLrequest_data = db.Column(db.Text,comment='请求数据')  # 请求数据response_data = db.Column(db.Text,comment='响应数据')  # 响应数据error_code = db.Column(db.String(50),comment='错误代码')  # 错误代码stack_trace = db.Column(db.Text,comment='堆栈追踪')  # 堆栈追踪hostname = db.Column(db.String(100),comment='服务器主机名')  # 服务器主机名context = db.Column(db.String(255),comment='上下文信息')  # 上下文信息def __repr__(self):return f"<ErrorLog(id={self.id}, ip_address={self.ip_address}, level={self.level}, message={self.message})>"

2.  编写日志记录静态方法

    # db.session 进行数据提交等操作@staticmethoddef log_message(session, exception=None, user_id=None,error_code=None,level=None, message=None, **kwargs):try:# 获取请求数据request_data=''if request.method == 'GET':request_data = str(dict(request.args))  # 直接获取查询参数elif request.method == 'POST':if request.is_json:request_data = str(request.get_json())  # 获取 JSON 数据else:request_data = str(request.form)  # 获取表单数据# 获取请求的其他信息ip_address = request.remote_addr  # 获取客户端IP地址url = request.url  # 获取请求的URLresponse_data = str(kwargs.get('response_data', ''))  # 获取响应数据stack_trace = traceback.format_exc() if exception else ""  # 获取堆栈追踪hostname = socket.gethostname()  # 获取服务器主机名context = kwargs.get('context', 'Production')  # 上下文(默认生产环境)if not message:message = str(exception) if exception else "Unknown error"# 检查错误响应数据并跳过日志记录try:# 将响应数据从字符串转换为字典response_dict = json.loads(response_data)if isinstance(response_dict, dict) and response_dict.get("message") == "内部服务器错误":return  # 跳过日志记录except json.JSONDecodeError:# 如果无法解析 JSON,则跳过判断pass# print(user_id)# 创建并保存日志条目log = Log(user_id=user_id if user_id else 0,level=level,message=message,ip_address=ip_address,url=url,request_data=request_data,response_data=response_data,stack_trace=stack_trace,hostname=hostname,context=context,method=request.method,module=request.blueprint,error_code=error_code,)# 保存日志条目db.session.add(log)db.session.commit()except Exception as e:print(e)pass

3. 在Flask中捕获请求日志

在Flask中,我们可以通过使用 after_request 钩子来捕获请求信息。这个钩子在每次请求处理完毕后执行,适合用于记录日志。示例如下:

# 请求成功日志记录
@app.after_request
def after_request(response):# 获取当前用户信息user_id = Nonelevel = "INFO"  # 你可以根据需要动态设置日志级别,如根据响应状态码判断message = "请求成功!"  # 请求成功的默认信息# 记录日志try:current_user = get_jwt_identity()# 获取用户信息(从数据库中获取用户信息做对比)user_info = db.session.query(User).filter(User.username == current_user).first()user_id = user_info.idexcept RuntimeError as e:# 捕获没有 JWT 时抛出的 RuntimeError 异常# 不做任何事情,直接跳过日志记录passexcept Exception as e:print(e)pass# 如果响应处于 passthrough 模式,则不能直接访问 response.dataif not response.direct_passthrough:# 正常情况下获取响应数据并转化为文本response_data = response.get_data(as_text=True)else:# 如果是 passthrough 模式,说明是流式响应或直接传递模式response_data = "{}"  # 或者根据需求设置适当的默认值if user_id:Log.log_message(db.session,user_id=user_id if user_id else 0,level=level,message=message,response_data=response_data,context="Production",  # 可选的环境信息error_code=200,)return response

在这个例子中,我们通过 after_request 钩子来处理每个请求后执行的日志记录。获取响应数据时,根据响应的类型决定是否直接获取 response.data

4. 捕获异常并记录错误日志

在实际开发中,应用程序往往会遇到异常。为了保证日志的完整性,我们可以捕获异常并将其记录下来。特别是对于HTTP 500类错误,应该记录详细的堆栈信息。

# 异常处理日志记录
@app.errorhandler(Exception)
def handle_exception(e):# 捕获所有异常,记录日志level = "ERROR"message = str(e)  # 将异常转换为字符串stack_trace = traceback.format_exc()  # 获取堆栈追踪# 获取当前用户信息user_id = Nonetry:current_user = get_jwt_identity()user_info = db.session.query(User).filter(User.username == current_user).first()user_id = user_info.idexcept RuntimeError:# 如果没有 JWT 则不记录用户IDpassif user_id:# 记录异常日志Log.log_message(db.session,exception=e,user_id=user_id,level=level,message='请求失败!',stack_trace=stack_trace,context="Production",error_code=500,)print(message)# 返回通用的500错误响应return {"message": "内部服务器错误"}, 500

在这个例子中,我们捕获了通用的异常,并将错误信息、堆栈追踪以及其他日志信息保存到数据库。

5. 编写日志接口数据展示

from flask import Response, jsonify, Flask, request, Blueprint,url_for
from configs import *
from modules.Tables import *
from sqlalchemy import func# 创建蓝图,对应的register目录(激活操作视图)
log_view = Blueprint('log_view', __name__)# 日志信息展示
@log_view.route('/log_data', methods=['GET'])
@jwt_required()
def log_data():# 获取分页参数page = request.args.get('page', default=1, type=int)  # 当前页码per_page = request.args.get('per_page', default=15, type=int)  # 每页显示条目数量level = request.args.get('level')  # 日志等级# 定义筛选列表filters = []# 当筛选条件存在时添加到列表if level:filters.append(Log.level == level)# 构建查询条件query = and_(*filters) if filters else True  # 如果 filters 为空,默认条件为 True# 查询主区域点并进行分页pagination = db.session.query(Log.id,Log.user_id,Log.ip_address, Log.level,Log.message,Log.module,Log.method,Log.url,Log.request_data, Log.response_data,Log.error_code, Log.stack_trace,Log.hostname,Log.context,Log.created_at).filter(query).paginate(page=page, per_page=per_page, error_out=False)# 获取分页后的数据data_list = [{'id': item.id,'user_id': item.user_id,'ip_address': item.ip_address,'level': item.level,'message': item.message,'module': item.module,'method': item.method,'url': item.url,'request_data': item.request_data if item.response_data else item.stack_trace,'response_data': item.response_data,'error_code': item.error_code,# 'stack_trace':item.stack_trace,'hostname':item.hostname,'context':item.context,'created_at': format_datetime(item.created_at),}for item in pagination.items]# 构造返回结果,包括分页信息response = {'code': 200,'data': data_list,'pagination': {'current_page': pagination.page,'total_pages': pagination.pages,'total_items': pagination.total,'per_page': pagination.per_page}}return jsonify({'code':200,'data':response})

 6. 写入数据展示

三. 日志信息格式处理问题

1. 如何处理流式响应(Passthrough)

Flask中的流式响应(passthrough)不允许直接访问 response.data,因此需要特别处理。通过 response.get_data(as_text=True) 方法,我们可以安全地获取响应数据并将其存储到日志中。如果响应不可序列化(如流式数据),可以跳过或记录默认值。

if not response.direct_passthrough:response_data = response.get_data(as_text=True)
else:response_data = "Non-serializable response"

2. 如何记录响应数据(如JSON响应)

对于返回JSON数据的响应,我们可以通过 response.get_data(as_text=True) 获取响应体的内容。这种方式适用于大多数JSON响应,确保我们可以将响应内容记录到日志中。

例如,在捕获日志时,我们可以如下处理响应数据:

response_data = response.get_data(as_text=True)

对于非JSON响应,使用 str() 也能保证将其转化为可记录的格式。

3. 总结与优化建议

  • 在Flask应用中,通过 @app.after_request 钩子可以轻松地记录每次请求的日志。
  • 根据不同的请求方法(GET/POST)和响应类型(JSON、流式数据等),动态调整日志记录方式。
  • 使用 try-except 语句捕获异常,并记录详细的错误信息以帮助后期的调试和维护。

通过这些方法,我们可以高效、全面地记录Flask应用中的日志,并为后期的性能优化、故障排查提供支持。

四 . 结尾

日志记录是开发和运维过程中不可或缺的一部分,它能帮助我们及时发现问题并做出调整。通过本文介绍的日志记录方式,我们能够方便地捕获请求和响应的详细信息,同时处理各种异常和特殊情况。希望这篇文章能够帮助你更好地理解并实现Flask中的日志记录。

相关文章:

Flask实现高效日志记录模块

目录 一. 简介&#xff1a; 1. 为什么需要请求日志 二. 日志模块组成 1. 对应日志表创建&#xff08;包含日志记录的关键字段&#xff09; 2. 编写日志记录静态方法 3. 在Flask中捕获请求日志 4. 捕获异常并记录错误日志 5. 编写日志接口数据展示 6. 写入数据展…...

基于python深度学习遥感影像地物分类与目标识别、分割

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB&#xff0c;遥感大数据时…...

Spring有哪些缺点?

大家好&#xff0c;我是锋哥。今天分享关于【Spring有哪些缺点?】面试题。希望对大家有帮助&#xff1b; Spring有哪些缺点? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring框架是一个广泛使用的企业级Java开发框架&#xff0c;提供了丰富的功能和强大的灵…...

linux学习【7】Sourc Insight 4.0设置+操作

目录 1.Source Insight是什么&#xff1f;2.需要哪些配置&#xff1f;3.怎么新建项目4.一些问题的解决1.中文乱码问题 5.常规使用1. 在工程中打开文件2. 在文件中查看函数或变量的定义3. 查找函数或变量的引用4. 快捷键 按照这个设置就可以了&#xff0c;下面的设置会标明设置理…...

dify实现分析-rag-关键词索引的实现

概述 在dify中有两种构建索引的方式&#xff0c;一种是经济型&#xff0c;另一种是高质量索引&#xff08;通过向量数据库来实现&#xff09;。其中经济型就是关键词索引&#xff0c;通过构建关键词索引来定位查询的文本块&#xff0c;而关键词索引的构建是通过Jieba这个库来完…...

PHP2(WEB)

##解题思路 打开页面什么线索都没有&#xff0c;目录扫描只是扫出来一个index.php&#xff0c;而源代码没有东西&#xff0c;且/robots.txt是不允许访问的 于是一番查询后发现&#xff0c;有个index.phps的文件路径&#xff0c;里头写着一段php的逻辑&#xff0c;对url的id参数…...

黑盒测试、白盒测试、单元测试、集成测试、系统测试、验收测试的区别与联系

黑盒测试 vs. 白盒测试 vs. 其他测试类型&#xff08;单元测试、集成测试、系统测试、验收测试&#xff09;的区别与联系 一、黑盒测试&#xff08;Black-box Testing&#xff09; 定义&#xff1a;不关心代码内部实现&#xff0c;只关注输入和输出是否符合预期。特点&#x…...

Halcon 3D加快表面匹配速度

文章目录 gen_box_object_model_3d 创建一个代表盒子的 3D 物体模型write_surface_model — 将表面模型写入文件read_surface_model — 将表面模型读取prepare_object_model_3d - 为某个操作准备三维对象模型select_points_object_model_3d - 对 3D 物体模型的属性应用阈值。se…...

Linux系统编程之高级信号处理

概述 在前一篇文章中&#xff0c;我们介绍了signal函数、sigaction函数等基本的信号处理方法。在本篇中&#xff0c;我们将介绍信号处理的一些高级用法&#xff0c;包括&#xff1a;阻塞与解除阻塞、定时器等。 阻塞与解除阻塞 有时候&#xff0c;我们不希望某个信号立即被处理…...

Ollama 本地GUI客户端:为DeepSeek用户量身定制的智能模型管理与交互工具

Ollama 本地GUI客户端&#xff1a;为DeepSeek用户量身定制的智能模型管理与交互工具 相关资源文件已经打包成EXE文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Python相关程序案例&#xf…...

基于SSM的《计算机网络》题库管理系统(源码+lw+部署文档+讲解),源码可白嫖!

摘 要 《计算机网络》题库管理系统是一种新颖的考试管理模式&#xff0c;因为系统是用Java技术进行开发。系统分为三个用户进行登录并操作&#xff0c;分别是管理员、教师和学生。教师在系统后台新增试题和试卷&#xff0c;学生进行在线考试&#xff0c;还能对考生记录、错题…...

对Revit事务机制的一些推测

什么是事务机制 首先&#xff0c;什么是事务机制。软件事务机制是指一种在软件系统中用于管理一系列操作的方法&#xff0c;这些操作要么全部成功完成&#xff0c;要么全部失败&#xff0c;不会出现部分完成的情况。事务机制确保了数据的一致性和完整性&#xff0c;特别是在并…...

软件架构设计:网络基础

一、计算机网络概述 计算机网络的定义 计算机网络是通过通信设备和线路将分散的计算机系统连接起来&#xff0c;实现资源共享和信息传递的系统。 计算机网络的分类 按覆盖范围&#xff1a;局域网&#xff08;LAN&#xff09;、城域网&#xff08;MAN&#xff09;、广域网&…...

《微软量子芯片:开启量子计算新纪元》:此文为AI自动生成

量子计算的神秘面纱 在科技飞速发展的今天,量子计算作为前沿领域,正逐渐走进大众的视野。它宛如一把神秘的钥匙,有望开启未来科技变革的大门,而微软量子芯片则是这把钥匙上一颗璀璨的明珠。 量子计算,简单来说,是一种遵循量子力学规律调控量子信息单元进行计算的新型计算…...

RocksDB Bloom Filter 如何避免假阳性问题探索

1. 引言&#xff1a;Bloom Filter 的机遇与挑战 Bloom Filter 是数据库系统中广泛使用的概率数据结构&#xff0c;它通过极小的内存开销快速判断一个键是否可能存在于磁盘文件中&#xff08;如 LSM-Tree 的 SSTable&#xff09;。然而&#xff0c;其核心缺陷是存在假阳性&…...

SpringBoot+Vue+Mysql苍穹外卖

一.项目介绍 1.项目内容 苍穹外卖是一款为大学学子设计的校园外卖服务软件&#xff0c;旨在提供便捷的食堂外卖送至宿舍的服务。该软件包含系统管理后台和用户端&#xff08;微信小程序&#xff09;两部分&#xff0c;支持在线浏览菜品、添加购物车、下单等功能&#xff0c;并…...

网络运维学习笔记 018 HCIA-Datacom综合实验02

文章目录 综合实验2sw3&#xff1a;sw4&#xff1a;gw&#xff1a;core1&#xff08;sw1&#xff09;&#xff1a;core2&#xff08;sw2&#xff09;&#xff1a;ISP 综合实验2 sw3&#xff1a; vlan 2 stp mode stp int e0/0/1 port link-type trunk port trunk allow-pass v…...

在 Java 中解析 JSON 数据

例子解析以下JSON数据 {"code":0,"msg":"成功","data": [{ "host":"1068222.com", "port":"", "m_token":"490e20e70e7de5f21a24b14c12a393f6", "categ…...

QT 引入Quazip和Zlib源码工程到项目中,无需编译成库,跨平台,压缩进度

前言 最近在做项目时遇到一个需求&#xff0c;需要将升级的文件压缩成zip&#xff0c;再进行传输&#xff1b; 通过网络调研&#xff0c;有许多方式可以实现&#xff0c;例如QT私有模块的ZipReader、QZipWriter&#xff1b;或者第三方库zlib或者libzip或者quazip等&#xff1…...

C++ 互斥锁的使用

mutex std::mutex 是C标准库中用于线程同步的互斥锁机制&#xff0c;主要用于保护共享资源&#xff0c;避免多个线程同时访问导致的竞态条件。 它提供了以下功能&#xff1a; 加锁&#xff08;lock&#xff09;&#xff1a;阻塞当前线程&#xff0c;直到获取锁。 解锁&#…...

使用 deepseek实现 go语言,读取文本文件的功能,要求支持 ascii,utf-8 等多种格式自适应

使用 deepseek实现 go语言&#xff0c;读取文本文件的功能&#xff0c;要求支持 ascii&#xff0c;utf-8 等多种格式自适应我要用 chatgpt&#xff0c;也问过&#xff0c;但是比 deepseek 还是差一个级别&#xff0c;具体如下&#xff1a; package mainimport ("bufio&qu…...

车载诊断架构 --- LIN节点路由转发注意事项

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...

Eclipse2024中文汉化教程(图文版)

对应Eclipse,部分人需要中文汉化,本章教程,介绍如何对Eclipse进行汉化的具体步骤。 一、汉化前的Eclipse 默认安装Eclipse的时候,默认一般都是English的,我当前版本是使用的是2024-06版本的Eclipse。 二、汉化详细步骤 点击上方菜单选项卡,Hep——Install New Software……...

网络协议相关知识有哪些?

前言 网络协议的基础是OSI和TCP/IP模型,这两个模型是理解协议分层的关键。 正文(仅是个人理解,如有遗漏望海涵) 网络协议是网络中设备间通信的规则和标准,涉及数据传输、路由、错误控制等多个方面。以下是网络协议相关知识的系统梳理: 一、网络协议分层模型 1、OSI七…...

医院安全(不良)事件上报系统源码,基于Laravel8开发,依托其优雅的语法与强大的扩展能力

医院安全&#xff08;不良&#xff09;事件上报系统源码 系统定义&#xff1a; 规范医院安全&#xff08;不良&#xff09;事件的主动报告&#xff0c;增强风险防范意识&#xff0c;及时发现医院不良事件和安全隐患&#xff0c;将获取的医院安全信息进行分析反馈&#xff0c;…...

【第一节】C++设计模式(创建型模式)-工厂模式

目录 前言 一、面向对象的两类对象创建问题 二、解决问题 三、工厂模式代码示例 四、工厂模式的核心功能 五、工厂模式的应用场景 六、工厂模式的实现与结构 七、工厂模式的优缺点 八、工厂模式的扩展与优化 九、总结 前言 在面向对象系统设计中&#xff0c;开发者常…...

分发糖果(力扣135)

题目说相邻的两个孩子中评分更高的孩子获得的糖果更多&#xff0c;表示我们既要考虑到跟左边的孩子比较&#xff0c;也要考虑右边的孩子&#xff0c;但是我们如果两边一起考虑一定会顾此失彼。这里就引入一个思想&#xff1a;先满足右边大于左边时的糖果分发情况&#xff0c;再…...

爬虫小案例豆瓣电影top250(json格式)

1.json格式&#xff08;仅供学习参考&#xff09; import requests, json, jsonpathclass Start(object):# 类实例化时会执行def __init__(self):self.headers {user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.…...

RTSP场景下RTP协议详解及音视频打包全流程

RTSP场景下RTP协议详解及音视频打包全流程 一、RTSP与RTP的关系 RTSP&#xff1a;负责媒体会话控制&#xff08;DESCRIBE、SETUP、PLAY、PAUSE&#xff09;&#xff0c;通过SDP协商传输参数&#xff08;端口、编码格式、封装模式&#xff09;。RTP&#xff1a;实际传输音视频数…...

关于Transparent native-to-ascii conversion

1、功能 自动转换ASCII编码&#xff0c;即在文件系统上&#xff0c;文件的编码格式为ascii编码&#xff0c;在编辑器&#xff08;idea/pycharm&#xff09;中&#xff0c;其展现结果为配置的编码格式&#xff0c;仅展现方便阅读 使用UTF-8并勾选自动转换ASCII编码结果&#x…...