aiolocals can be used to track any task-local state and comes with integration with aiohttp to track the necessary bits to track request ids across log statements.

Simple example

This example tracks state across all coroutines in the current task. The output will be “ is baz”:

foo = aiolocals.Local()

def do_nothing():
  yield from asyncio.sleep(.1)
  print(" is {}".format(

with Context(locals=[foo]): = "baz"
  yield from do_nothing()

Request tracking

To use the built-in aiohttp request tracking functionality, first initialize the logs to include request id information:


Next, add the context tracking middleware to your aiohttp.web application:

myapp = aiohttp.web.Application(middlewares=[aiolocals.context_middleware_factory])

Now, every log message fired within the handling of a request will include the request id and path information. Ids coming from incoming requests are automatically handled by using the value of the “X-REQUEST-ID” header as the request id.

Job tracking

To track log messages from a single job execution, you can use the job_context() decorator:

def myjob():
  yield from asyncio.sleep(.1)
  print("job complete: {}".format(

State tracking across tasks

The state tracking works fine as long as there is one root task, but what if your HTTP request handling needs to spawn off other tasks, but you want to keep the same state in these new tasks? Use ‘aiolocals.wrap_async’ to spawn a new task and know that it’ll get a copy of the state automatically.

This example will fire off a background task in the process of handling a request, printing the same request id to the console.

def backgrounded_task():
  print("background id: {}".format(

def handler(request):
  print("request: {}".format(