首页 > 其他分享 >通过钩子函数+Traceid实现Flask链路追踪

通过钩子函数+Traceid实现Flask链路追踪

时间:2024-06-02 15:14:36浏览次数:21  
标签:traceid trace Flask 链路 request headers Traceid time msg

背景

在flask web中我们通常需要一个traceid作为调用参数传递给全链路各个调用函数

  1. 需要针对一次请求创建一个唯一的traceid:这里用uuid去简化代替
  2. 我们需要保证traceid不被污染,在每个请求期间存在,在请求结束销毁且线程独立:这里通过flask中的g对象来存储线程内的数据
  3. 由于我们使用g对象来存储,那么当接口中发起新的请求时候,新请求会创建新的g对象,此时g对象为空,我们需要让traceid可以在多个请求中共享数据:这里通过请求头中增加traceid来传递

实现

首先定义二个主要函数

  • 定义一个请求开始的时候需要调用的函数,用于初始化traceid或者获取上一个请求中的traceid以及其他一些相关请求参数
  • 定义一个请求结束的时候需要调用的函数,用于请求结束的日志响应报文收尾记录。
import requests
from flask import request, g
import time
from flask import Flask

def get_uuid():
    import uuid
    return str(uuid.uuid4()).replace('-', '')


def trace_add_log_record(event_des='',msg_dict={},remarks=''):
    #trace_links_index每次调用+1
    request.trace_links_index = request.trace_links_index + 1
    logs = {
        'traceid': g.traceid,
        'trace_index': request.trace_links_index,
        'event_des': event_des,
        'msg_dict': msg_dict,
        'remarks': remarks
    }
    print(logs)

def trace_start_log_record_handler():
    # 获取traceid,如果存在则使用,否则生成一个
    if "traceid" in request.headers:
        g.traceid =  request.headers['traceid']
    else:
        g.traceid = get_uuid()
    # 初始化trace_links_index
    request.trace_links_index = 0
    # 记录开始时间
    request.start_time = time.time()
    log_msg = {
        'headers': request.headers,
        'url': request.url,
        'method': request.method,
        "request_data": request.args if request.method == "GET" else request.get_json(),
        'ip': request.headers.get("X-Real-IP") or request.remote_addr,
        'start_time': request.start_time
    }
    # 记录日志
    trace_add_log_record(event_des='start', msg_dict=log_msg)

def trace_end_log_record_handler(reponse):
    # 记录结束时间
    request.end_time = time.time()
    # 记录traceid到响应头
    reponse.headers.add('traceid', g.traceid)
    log_msg = {
        "end_time" : request.end_time,
        "cost_time": request.end_time - request.start_time,
        "status_code": reponse.status_code,
        "headers": reponse.headers,
        "response_data": reponse.data.decode('utf-8')
    }
    # 记录日志
    trace_add_log_record(event_des='end', msg_dict=log_msg)

接着,我们通过钩子函数去触发我们上述所写的两个重要函数

"""
写钩子函数在app中注册,还有一种写法
@app.before_request
def before_request2():
    print('before_request2')


@app.after_request
def after_request1(response):
    print('after_request1')

    return response
"""
#写钩子函数在app中注册
def register_handler(response):
    def before_request():
        trace_start_log_record_handler()
    def after_request(response):
        trace_end_log_record_handler(reponse=response)
        return response
    # 注册钩子函数
    response.before_request(before_request)
    response.after_request(after_request)

最后写测试接口进行测试

app = Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello, World!'

@app.route('/test')
def test():
    name = request.args.get('name')
    hello_world = requests.get('http://127.0.0.1:5000/', headers={'traceid': g.traceid})
    return name + hello_world.text

@app.route('/test2', methods=['POST'])
def test2():
    name = request.get_json().get('name')
    hello_world = requests.get('http://127.0.0.1:5000/', headers={'traceid': g.traceid})
    return name + hello_world.text

if __name__ == '__main__':

    register_handler(app)
    app.run(debug=True)

这样我们简单了完成了通过traceid把链路串联起来了

{'traceid': 'a5637579351c477a80090a88f5347088', 'trace_index': 1, 'event_des': 'start', 'msg_dict': {'headers': EnvironHeaders([('User-Agent', 'Apifox/1.0.0 (https://apifox.com)'), ('Content-Type', 'application/json'), ('Accept', '*/*'), ('Host', '127.0.0.1:5000'), ('Accept-Encoding', 'gzip, deflate, br'), ('Connection', 'keep-alive')]), 'url': 'http://127.0.0.1:5000/test?name=yetangjian', 'method': 'GET', 'request_data': ImmutableMultiDict([('name', 'yetangjian')]), 'ip': '127.0.0.1', 'start_time': 1717311086.757312}, 'remarks': ''}
{'traceid': 'a5637579351c477a80090a88f5347088', 'trace_index': 1, 'event_des': 'start', 'msg_dict': {'headers': EnvironHeaders([('Host', '127.0.0.1:5000'), ('User-Agent', 'python-requests/2.25.1'), ('Accept-Encoding', 'gzip, deflate'), ('Accept', '*/*'), ('Connection', 'keep-alive'), ('Traceid', 'a5637579351c477a80090a88f5347088')]), 'url': 'http://127.0.0.1:5000/', 'method': 'GET', 'request_data': ImmutableMultiDict([]), 'ip': '127.0.0.1', 'start_time': 1717311086.7663064}, 'remarks': ''}
{'traceid': 'a5637579351c477a80090a88f5347088', 'trace_index': 2, 'event_des': 'end', 'msg_dict': {'end_time': 1717311086.7663064, 'cost_time': 0.0, 'status_code': 200, 'headers': Headers([('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '13'), ('traceid', 'a5637579351c477a80090a88f5347088')]), 'response_data': 'Hello, World!'}, 'remarks': ''}
{'traceid': 'a5637579351c477a80090a88f5347088', 'trace_index': 2, 'event_des': 'end', 'msg_dict': {'end_time': 1717311086.7683115, 'cost_time': 0.010999441146850586, 'status_code': 200, 'headers': Headers([('Content-Type', 'text/html; charset=utf-8'), ('Content-Length', '23'), ('traceid', 'a5637579351c477a80090a88f5347088')]), 'response_data': 'yetangjianHello, World!'}, 'remarks': ''}

 

标签:traceid,trace,Flask,链路,request,headers,Traceid,time,msg
From: https://www.cnblogs.com/yetangjian/p/18227138

相关文章

  • 使用 Sleuth 和 Zipkin 实现分布式链路追踪
    SpringCloud微服务之间的调用关系,通常随着业务的不断扩张而变得越来越复杂。如果调用链路上任何一个服务出现问题或者网络超时,导致通过日志快速排查和定位问题非常困难。分布式链路追踪就可以轻松解决该场景所面临的问题,其中一种比较简单的方案是采用SpringCloudSleuthSprin......
  • 2024拼多多 最新理论+实战干货,从入门到精通全链路多角度学习-7节课
    基于最新规则理论结合实际的干货课程内容:012024年多多防比价新规则破局理论课与实操课.mp40224年多多强付费第二节课基础内功.mp40324年多多强付费第三节课直通车实操.mp40424年多多强付费第一节课市场定价格段,mp40524年多多自然流第一节课市场分析-small.mp40......
  • 一站式链路追踪:阿里云的端到端解决方案
    作者:涯海炎炎夏日,当你打开外卖APP购买奶茶却发现下单失败;五一佳节,当你自驾游途中发现导航响应缓慢,频繁错过路口;深更半夜,当你辅导孩子功课,却发现GPT应用迟迟无法应答。不知你有没有想过,这些程序运行的背后到底是怎样的世界,每一次点击,每一次交互,又到底发生了什么?如果你是一名......
  • 在 Flask 项目中配置 Session:简明指南
    在Flask项目中配置Session:简明指南本文介绍如何在Flask项目中配置会话1.Flask内置会话Flask自带会话管理功能,使用客户端Cookie存储会话数据。默认情况下,会话数据是签名的,以防止篡改,但未加密。因此,不建议在会话中存储敏感信息。Flask内置会话适用于小型应用或会话数......
  • M-LAG(跨设备链路聚合)二层基础配置
    一、拓扑结构  二、接口配制S6850_1S6850_2interfaceVlan-interface999ipaddress1.1.1.1255.255.255.252#interfaceFortyGigE1/0/53portlink-modebridgeportaccessvlan999#interfaceGigabitEthernet1/0/1portlink-modebridgecomboenablefiber......
  • 计算机毕业设计python-django生态评价网站系统flask框架
    网站主要使用的模式是管理员上传各地生态图片和一些土地,降雨,植被的数据,用户登录到网站上根据网站上的数据进行生态的评价,综合了多方面的想法和不同的建议,查看网站的人来说能够看到不同的想法,不局限于一种想法,也可以在网站上发表自己的看法,并作出相应的对策。采用前后端分离开发......
  • python-django学院校园失物招领管理系统flask框架
    当前大多数校园失物招领信息主要是由志愿者联合会来组织开展,开展形式主要通过在公共场所填写失物招领信息以及志愿者服务公众号来传播失物招领消息,该公众号主要发布失物招领信息,学生教师需要通过到现场或者志愿者公众号去了解,这种形式主要局限于失主与拾主的联系以及失主的寻物......
  • python+django高校学生兼职信息网站设计pycharm项目flask
     自高等教育改革化,人们普遍重点观点放在了注重学生的学习能力和社会实践之上。为了满足了人们对教育的渴求,保障了人受教育的权利,各高校采取了扩招,广开大门对每位求知好学之人。随着学校人员增多,大量的求职需求也初显了出来。在信息化的时代,人们已经不像从前挨家挨户的求职,投简......
  • 数据链路层的检错与纠错
    通讯链路都不是完全理想的。比特在传输过程中可能会产生比特差错,即1可能变成0,0也可能变成11帧包含m个数据位(即报文)和r个冗余位(即校验位)。假设帧的总长度为n,则有n=m+r。包含数据和校验位的n位单元,通常称为n位码字奇偶校验\(\color{red}{奇偶校验只能检测出错误,而无......
  • flask 配合 sqlite3 维护数据库的数据方法
    importjsonimportsqlite3con=sqlite3.connect("Test.db")cur=con.cursor()#==https://blog.csdn.net/GuoQiZhang/article/details/91344509数据库案例.cur.execute("CREATETABLEIFNOTEXISTSmed(idINTEGERPRIMARYKEY,dataTEXT)")c......