async safir.middleware.bind_logger(request: Request, handler: Handler) → StreamResponse

Bind request metadata to the context-local structlog logger.

This is an aiohttp.web middleware.

  • request – The aiohttp.web request.

  • handler – The application’s request handler.


The response with the logger key attached to it. This structlog-based logger is bound with context about the request. See Notes for details.

Return type



This middleware initializes a new response-local structlog logger with context bound to it. All logging calls within the context of a response include this context. This makes it easy to search, filter, and aggregate logs for a specififc request. For background, see

The context fields are:


A random UUID4 string that uniquely identifies the request.


The path of the request.


The http method of the request.

Logger name

By default, the logger is named for the logger_name attribute of the configuration object (app["safir/config"]). If that configuration is not set, the logger name falls back to __name__.


Setting up the middleware

Use the safir.middleware.setup_middleware function to set this up:

app = web.Application()
app["safir/config"] = Configuration()

Remember that bind_logger names the logger according to the logger_name attribute of the configuration, app["safir/config"].

Using the logger

Within a handler, you can access the logger directly from the safir/logger key of the request object:

async def get_index(request):
    logger = request["safir/logger"]"Logged message", somekey="somevalue")

If the request object is not available, you can still get the logger through the safir.logging.get_response_logger function:

from safir.logging import get_response_logger

logger = get_response_logger()"My message", somekey="somevalue")

Under the hood, you can also get this logger from the safir.logging.response_logger context variable. For example:

from safir.logging import response_logger

logger = response_logger.get()"My message", somekey="somevalue")

The response_logger.get() syntax is because response_logger is a contextvars.ContextVar. A ContextVar is isolated to each asyncio Task, which makes it great for storing context specific to each reponse.

The request["safir/logger"] and safir.logging.get_response_logger APIs are the best ways to get the logger.