经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python3 » 查看文章
通过钩子函数+Traceid实现Flask链路追踪
来源:cnblogs  作者:yetangjian  时间:2024/6/3 9:28:54  对本文有异议

背景

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

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

实现

首先定义二个主要函数

  • 定义一个请求开始的时候需要调用的函数,用于初始化traceid或者获取上一个请求中的traceid以及其他一些相关请求参数
  • 定义一个请求结束的时候需要调用的函数,用于请求结束的日志响应报文收尾记录。
  1. import requests
  2. from flask import request, g
  3. import time
  4. from flask import Flask
  5. def get_uuid():
  6. import uuid
  7. return str(uuid.uuid4()).replace('-', '')
  8. def trace_add_log_record(event_des='',msg_dict={},remarks=''):
  9. #trace_links_index每次调用+1
  10. request.trace_links_index = request.trace_links_index + 1
  11. logs = {
  12. 'traceid': g.traceid,
  13. 'trace_index': request.trace_links_index,
  14. 'event_des': event_des,
  15. 'msg_dict': msg_dict,
  16. 'remarks': remarks
  17. }
  18. print(logs)
  19. def trace_start_log_record_handler():
  20. # 获取traceid,如果存在则使用,否则生成一个
  21. if "traceid" in request.headers:
  22. g.traceid = request.headers['traceid']
  23. else:
  24. g.traceid = get_uuid()
  25. # 初始化trace_links_index
  26. request.trace_links_index = 0
  27. # 记录开始时间
  28. request.start_time = time.time()
  29. log_msg = {
  30. 'headers': request.headers,
  31. 'url': request.url,
  32. 'method': request.method,
  33. "request_data": request.args if request.method == "GET" else request.get_json(),
  34. 'ip': request.headers.get("X-Real-IP") or request.remote_addr,
  35. 'start_time': request.start_time
  36. }
  37. # 记录日志
  38. trace_add_log_record(event_des='start', msg_dict=log_msg)
  39. def trace_end_log_record_handler(reponse):
  40. # 记录结束时间
  41. request.end_time = time.time()
  42. # 记录traceid到响应头
  43. reponse.headers.add('traceid', g.traceid)
  44. log_msg = {
  45. "end_time" : request.end_time,
  46. "cost_time": request.end_time - request.start_time,
  47. "status_code": reponse.status_code,
  48. "headers": reponse.headers,
  49. "response_data": reponse.data.decode('utf-8')
  50. }
  51. # 记录日志
  52. trace_add_log_record(event_des='end', msg_dict=log_msg)

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

  1. """
  2. 写钩子函数在app中注册,还有一种写法
  3. @app.before_request
  4. def before_request2():
  5. print('before_request2')
  6. @app.after_request
  7. def after_request1(response):
  8. print('after_request1')
  9. return response
  10. """
  11. #写钩子函数在app中注册
  12. def register_handler(response):
  13. def before_request():
  14. trace_start_log_record_handler()
  15. def after_request(response):
  16. trace_end_log_record_handler(reponse=response)
  17. return response
  18. # 注册钩子函数
  19. response.before_request(before_request)
  20. response.after_request(after_request)

最后写测试接口进行测试

  1. app = Flask(__name__)
  2. @app.route('/')
  3. def hello_world():
  4. return 'Hello, World!'
  5. @app.route('/test')
  6. def test():
  7. name = request.args.get('name')
  8. hello_world = requests.get('http://127.0.0.1:5000/', headers={'traceid': g.traceid})
  9. return name + hello_world.text
  10. @app.route('/test2', methods=['POST'])
  11. def test2():
  12. name = request.get_json().get('name')
  13. hello_world = requests.get('http://127.0.0.1:5000/', headers={'traceid': g.traceid})
  14. return name + hello_world.text
  15. if __name__ == '__main__':
  16. register_handler(app)
  17. app.run(debug=True)

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

  1. {'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': ''}
  2. {'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': ''}
  3. {'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': ''}
  4. {'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': ''}

 

原文链接:https://www.cnblogs.com/yetangjian/p/18227138

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号