Request ID is stored in flask.g.request_id argument in flask's before_request. I am facing issue in logging this request id through "format" variable of the loguru for each and every request.
Well, you need to make use of the extra dict. You can setup your handler like that:
logger.add(sys.stderr, format="{time} - {level} - {extra[request_id]} - {message}")
logger.configure(extra={"request_id": None}) # Set global default value
Then, when you get access to the actual request_id value you need to bind() it to the logger:
def before_request():
logger = logger.bind(request_id=flask.g.request_id)
logger.info("Preparing the request...") # The "request_id" will appear in the logged message
Alternatively, you can use a format function so that the request_id can be retrieved dynamically at each logging call:
def formatter(record):
record["extra"]["request_id"] = flask.g.getattr("request_id", None)
return "{time} - {level} - {extra[request_id]} - {message}\n{exception}"
logger.add(sys.stderr, format=formatter)
Related and possibly useful functions are patch() and contextualize().
Thanks @Delgan for thee quick reply.
While trying out the first option i.e. binding request_id in before_request function, its available in the same file, but when we log the same request from other file, global default value (None) is getting printed.
Also, in before_request function its not able to reference the logger that we imported at the top. So we have to add a test_request_context and import one more time.
Problem with the formatter function was - AttributeError: '_AppCtxGlobals' object has no attribute 'getattr'
Appreciate all your help.
While trying out the first option i.e. binding request_id in before_request function, its available in the same file, but when we log the same request from other file, global default value (None) is getting printed.
Yeah, only the logger returned by logger.bind() got access to the request_id value. If you are using the logger in another file, you need to pass the request_id to the other file and call bind() again. Alternatively, you can use contextualize() like this:
def do_request():
with logger.contextualize(request_id=flask.g.request_id):
call_method_in_another_file()
I'm not sure this is suitable for use with before_request(), so the workaround using a dynamic format is probably better.
Also, in before_request function its not able to reference the logger that we imported at the top. So we have to add a test_request_context and import one more time.
Are you referring to the UnboundLocalError? This can be fixed by using logger_ = logger.bind(request_id=flask.g.request_id) for example (sorry, I should have thought of that).
Problem with the formatter function was - AttributeError: '_AppCtxGlobals' object has no attribute 'getattr'
My bad. It should be record["extra"]["request_id"] = getattr(flask.g, "request_id", None) instead.
Thanks @Delgan for the immediate response.
The formatter method helped me solve the issue. I had to use "with app.test_request_context():" for the method as it threw "RuntimeError: Working outside of application context." And "with app.app_context():" couldn't solve the issue.
Thanks a lot once again
Problem Solved
Most helpful comment
Well, you need to make use of the
extradict. You can setup your handler like that:Then, when you get access to the actual
request_idvalue you need tobind()it to thelogger:Alternatively, you can use a
formatfunction so that therequest_idcan be retrieved dynamically at each logging call:Related and possibly useful functions are
patch()andcontextualize().