如何用Python在Flask中获取单个请求的唯一ID?

在一个 flask 应用里面,我输出了各种日志,以结构化形式存到 ElasticSearch,我想把每个日志都归属到具体的请求,以做到可以按请求追溯。应该怎么得到(或生成)一个请求的唯一 ID 呢?

也就是说,用户请求一个地址,其处理过程中生成的一系列日志,和他下一次发起同样的请求所生成的日志,会归属到不同的请求 ID 上。
如何用Python在Flask中获取单个请求的唯一ID?

14 回复

我是直接 md5 当前的时间戳,取前面 16 位的。


在Flask里给每个请求搞个唯一ID,一个直接的办法就是用before_request钩子配合g对象。下面是个能直接跑的完整例子:

from flask import Flask, g, request
import uuid

app = Flask(__name__)

@app.before_request
def assign_request_id():
    # 把生成的唯一ID塞到g对象里,这样在整个请求周期都能访问
    g.request_id = str(uuid.uuid4())

@app.route('/')
def index():
    # 在视图函数里直接取用
    return f'当前请求的ID是: {g.request_id}'

@app.route('/api')
def api():
    # 另一个路由也能用
    return {'request_id': g.request_id}

if __name__ == '__main__':
    app.run(debug=True)

这里核心就两步:一是在before_request里用uuid.uuid4()生成一个唯一字符串,存到g.request_id;二是在任何需要的地方(比如视图函数、模板、或者别的处理函数)直接读g.request_id就行。g对象是Flask为每个请求单独准备的,请求结束就清空,所以不会串。

如果你用了像Gunicorn这种多worker的服务器,uuid.uuid4()生成的ID在理论上有极低概率重复,但对绝大多数Web应用来说完全够用。要是真有强唯一性要求,可以考虑组合时间戳、机器信息和随机数来生成。

总结:用before_request钩子和g对象来传递请求ID最直接。

uuid 啊,标准库

UUID 还得找时机生成并挂到 request 对象上,这个最早时机是什么时候?

其实我想知道的是 flask 内部不同的 request 上下文是否有什么标识可以区分,比如 id(request)id(request.some_attr) 是否可以。

钩子放到 g
g.uuid
大概思路

分享一个其他方法,如果前面有 nginx 的话,

nginx v1.11 支持 $request_id 变量;通过 proxy_set_header X-Request-Id $request_id 的方式把请求唯一 ID 写到 header 中

在 flask 中通过获取头信息的方式即可

多谢,通过 Nginx 是不错的方法,这样能和 Nginx 日志整合到一起来追溯。

hash 成 md5 要消耗时间性能的



当初因为 uuid 太长了,就索性简单点自己生成了。

目前最佳实践是通过 nginx 生成,带到后端的同时返回给前端,方便问题定位。其实 request_id 还可以带上语义,比如说当前时间、机器 ip 等

你可以考虑用 xid 方案 比 uuid 短 可排序 带时间戳段位 机器应该能支持几百台规模 再多就不行了 当然你可以自己做个扩容实现

https://gist.github.com/wonderbeyond/ae7c27be9536d65966f5d94464df0d96

实际需求很简单,我实现的也很简单。
可为什么以 “flask request id” 为关键词找到的别的实现看起来有点复杂而且有点绕,或者完全不是一个意思:

- https://pypi.python.org/pypi/flask-request-id-middleware/1.0
- https://pypi.python.org/pypi/flask-request-id/0.1
- https://github.com/Workable/flask-log-request-id

回到顶部