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

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. 写入数据展…...

scroll、offset、client三大家族和getBoundingClientRect方法

scroll、offset、client三大家族和getBoundingClientRect方法 1.offset(只能读,不能修改&#xff09;2.client(只能读,不能修改&#xff09;3.scroll滚动家族4.getBoundingClientRect方法 1.offset(只能读,不能修改&#xff09; offsetParent:离当前元素最近的有定位的祖先元素…...

JWT 令牌

目录 一、JWT 1、什么是JWT 2、JWT的组成 3、JJWT签发与验证token 1、创建token 2、解析token 3、设置过期时间 4、自定义claims 前言&#xff1a; 在现代Web应用和微服务架构中&#xff0c;用户身份验证和信息安全传输是核心问题。JSON Web Token&#xff08;J…...

Python基于Flask的豆瓣Top250电影数据可视化分析与评分预测系统(附源码,技术说明)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…...

JavaScript数组-遍历数组

在JavaScript中&#xff0c;数组是一种非常常用的数据结构&#xff0c;用于存储一系列有序的数据项。无论是处理简单的列表还是复杂的数据集合&#xff0c;遍历数组都是我们经常需要执行的操作之一。本文将详细介绍几种常见的遍历数组的方法&#xff0c;并讨论它们各自的优缺点…...

基于Flask的第七次人口普查数据分析系统的设计与实现

【Flask】基于Flask的第七次人口普查数据分析系统的设计与实现&#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 基于Flask的人口普查可视化分析系统 二、项目界面展示 登录/注册 首页/详情 …...

解决DeepSeek服务器繁忙的有效方法

全球42%的企业遭遇过AI工具服务器过载导致内容生产中断&#xff08;数据来源&#xff1a;Gartner 2025&#xff09;。当竞品在凌晨3点自动发布「智能家居安装指南」时&#xff0c;你的团队可能正因DeepSeek服务器繁忙错失「净水器保养教程」的流量黄金期⏳。147SEO智能调度系统…...

分词器(Tokenizer) | 有了分词器,为什么还需要嵌入模型

文章目录 什么是tokenizer有了分词器&#xff0c;为什么还需要嵌入模型分词器为什么在transformers 里Hugging Face的Tokenizer大模型不同tokenizer训练效果对比分词器库选择当前顶尖大模型所采用的 Tokenizer 方法与词典大小 参考 什么是tokenizer Tokenizers huggingface官方…...

VisionTransformer(ViT)与CNN卷积神经网络的对比

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

计算机视觉+Numpy和OpenCV入门

Day 1&#xff1a;Python基础Numpy和OpenCV入门 Python基础 变量与数据类型、函数与类的定义、列表与字典操作文件读写操作&#xff08;读写图像和数据文件&#xff09; 练习任务&#xff1a;写一个Python脚本&#xff0c;读取一个图像并保存灰度图像。 import cv2 img cv2.im…...

Vue 3 工程化打包工具:从理论到实践 (下篇)

引言 在前端开发中&#xff0c;打包工具是工程化的重要组成部分。Vue 3 作为当前流行的前端框架&#xff0c;其工程化离不开高效的打包工具。打包工具不仅能够将代码、样式、图片等资源进行优化和压缩&#xff0c;还能通过模块化、代码分割等功能提升应用的性能。本文将深入探…...

java经验快速学习python!

title: java经验快速学习python&#xff01; date: 2025-02-19 01:52:05 tags: python学习路线 java经验快速学习python&#xff01; 本篇文档会一直更新&#xff01;&#xff01;&#xff01;变量、分支结构、循环结构、数据结构【列表、元组、集合字典】python常用内置函数元…...

爬虫破解网页禁止F12

右击页面显示如下 先点击f12再输入网址&#xff0c;回车后没有加载任何数据 目前的一种解决方法&#xff1a; 先 AltD &#xff0c;再 CtrlShifti...

从零开始构建一个语言模型中vocab_size(词汇表大小)的设定规则

从零开始构建一个语言模型就要设计一个模型框架,其中要配置很多参数。在自然语言处理任务中,vocab_size(词汇表大小) 的设定是模型设计的关键参数之一,它直接影响模型的输入输出结构、计算效率和内存消耗。 本文是在我前文的基础上讲解的:从零开始构建一个小型字符级语言…...

Jenkins插件管理切换国内源地址

安装Jenkins 插件时&#xff0c;由于访问不了国外的插件地址&#xff0c;会导致基本插件都安装失败。 不用着急&#xff0c;等全部安装失败后&#xff0c;进入系统&#xff0c;修改插件源地址&#xff0c;重启后在安装所需插件。 替换国内插件更新地址 选择&#xff1a;系统…...

Q - learning 算法是什么

Q - learning 算法是什么 Q - learning 算法是一种经典的无模型强化学习算法,由克里斯沃特金斯(Chris Watkins)在 1989 年提出。它被广泛应用于解决各种决策问题,尤其适用于智能体在环境中通过与环境交互来学习最优策略的场景。下面从基本概念、核心公式、算法流程和特点几…...

nasm - console 32bits

文章目录 nasm - console 32bits概述笔记my_build.batnasm_main.asm用VS2019写个程序&#xff0c;按照win32方式编译&#xff0c;比较一下。备注END nasm - console 32bits 概述 看到一个nasm的例子(用nasm实现一个32bits控制台的程序架子) 学习一下 笔记 my_build.bat ec…...

11.编写前端内容|vscode链接Linux|html|css|js(C++)

vscode链接服务器 安装VScode插件 Chinese (Simplified) (简体中⽂) Language Pack for Visual Studio CodeOpen in BrowserRemote SSH 在命令行输入 remote-ssh接着输入 打开配置文件&#xff0c;已经配置好主机 点击远程资源管理器可以找到 右键链接 输入密码 …...

【deepseek-r1模型】linux部署deepseek

1、快速安装 Ollama 下载&#xff1a;Download Ollama on macOS Ollama 官方主页&#xff1a;https://ollama.com Ollama 官方 GitHub 源代码仓库&#xff1a;https://github.com/ollama/ollama/ 官网提供了一条命令行快速安装的方法。 &#xff08;1&#xff09;下载Olla…...

【Github每日推荐】-- 2024 年项目汇总

1、AI 技术 项目简述OmniParser一款基于纯视觉的 GUI 智能体&#xff0c;能够准确识别界面上可交互图标以及理解截图中各元素语义&#xff0c;实现自动化界面交互场景&#xff0c;如自动化测试、自动化操作等。ChatTTS一款专门为对话场景设计的语音生成模型&#xff0c;主要用…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

PAN/FPN

import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...