Closed
Description
Long story short
We want to attach context from contextvars to logger message
Problem
When user tries to put some information to logs (i.e. request_id) there's no access to contextvars, because user can only put something to contextvars in middleware
I propose to add new signal, like response.on_prepare, but for request, where I can put something to contextvars, for example mark this request with uuid.
see example (python 3.7 only):
import logging
import uuid
from logging.config import dictConfig
import contextvars
from aiohttp import web
from aiohttp.abc import AbstractAccessLogger
REQUEST_ID = contextvars.ContextVar("request_id")
class AsyncAccessLogger(AbstractAccessLogger):
def log(self, request, response, time):
print(("AsyncAccessLogger", REQUEST_ID.get()))
self.logger.info("test")
class ContextFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
record.__dict__.update({"request_id": REQUEST_ID.get()})
return True
def setup_logs():
dictConfig(
config={
"version": 1,
"disable_existing_loggers": False,
"filters": {"request_context": {"()": "start_log_test.ContextFilter"}},
"handlers": {"stdout": {"level": "DEBUG", "class": "logging.StreamHandler"}},
"loggers": {
"aiohttp.access": {"handlers": ["stdout"], "level": "DEBUG"},
"aiohttp.server": {"handlers": ["stdout"], "level": "DEBUG"},
},
}
)
@web.middleware
async def request_id(request, handler):
REQUEST_ID.set(str(uuid.uuid4()))
return await handler(request)
async def get_(request: web.Request):
print(("REQUEST", REQUEST_ID.get()))
# for exception
1 / 0
return web.json_response()
def main():
app = web.Application(middlewares=[request_id])
app.add_routes([web.get("/", get_)])
setup_logs()
web.run_app(app, access_log_class=AsyncAccessLogger, port=8088)
if __name__ == "__main__":
main()after request
======== Running on http://0.0.0.0:8088 ========
(Press CTRL+C to quit)
('REQUEST', '3bd497ec-1df1-4deb-842d-d12197a9c9a1')
Error handling request
Traceback (most recent call last):
File ".../code/venvs/aiohttp_logs/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 418, in start
resp = await task
File ".../code/venvs/aiohttp_logs/lib/python3.7/site-packages/aiohttp/web_app.py", line 458, in _handle
resp = await handler(request)
File ".../code/venvs/aiohttp_logs/lib/python3.7/site-packages/aiohttp/web_middlewares.py", line 119, in impl
return await handler(request)
File ".../code/python/aiohttp_logs/start_log_test.py", line 42, in request_id
return await handler(request)
File ".../code/python/aiohttp_logs/start_log_test.py", line 48, in get_
1 / 0
ZeroDivisionError: division by zero
Unhandled exception
Traceback (most recent call last):
File ".../code/venvs/aiohttp_logs/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 455, in start
self.log_access(request, resp, loop.time() - now)
File ".../code/venvs/aiohttp_logs/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 348, in log_access
self.access_logger.log(request, response, time)
File ".../code/python/aiohttp_logs/start_log_test.py", line 14, in log
print(("AsyncAccessLogger", REQUEST_ID.get()))
LookupError: <ContextVar name='request_id' at 0x10aee7d00>
If we agree on design/architecture, I can work on pull request or maybe someone can give us a hint how to achieve that :)
Thanks!
Metadata
Assignees
Labels
No labels