mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-27 23:28:03 +09:00
43 lines
1.2 KiB
Python
43 lines
1.2 KiB
Python
"""Request-ID propagation for API responses, errors, and diagnostic logs."""
|
|
|
|
import re
|
|
import secrets
|
|
|
|
from flask import g, has_request_context, request
|
|
|
|
|
|
REQUEST_ID_HEADER = 'X-Request-ID'
|
|
_SAFE_REQUEST_ID = re.compile(r'^[A-Za-z0-9._:-]{1,128}$')
|
|
|
|
|
|
def _new_request_id():
|
|
return secrets.token_hex(16)
|
|
|
|
|
|
def get_request_id(*, create=False):
|
|
"""Return this request's ID, optionally creating it for direct handlers."""
|
|
if not has_request_context():
|
|
return None
|
|
request_id = getattr(g, 'request_id', None)
|
|
if request_id is None and create:
|
|
request_id = _new_request_id()
|
|
g.request_id = request_id
|
|
return request_id
|
|
|
|
|
|
def register_request_id(app):
|
|
"""Accept a safe caller ID or generate one and echo it on API responses."""
|
|
|
|
@app.before_request
|
|
def assign_request_id():
|
|
if not request.path.startswith('/api/'):
|
|
return
|
|
supplied = (request.headers.get(REQUEST_ID_HEADER) or '').strip()
|
|
g.request_id = supplied if _SAFE_REQUEST_ID.fullmatch(supplied) else _new_request_id()
|
|
|
|
@app.after_request
|
|
def expose_request_id(response):
|
|
if request.path.startswith('/api/'):
|
|
response.headers[REQUEST_ID_HEADER] = get_request_id(create=True)
|
|
return response
|