Context Binding

Attach request- or task-scoped metadata to every log entry via the logger’s context API.

bind {#bind}

logger.bind(**kwargs) -> Logger
async_logger.bind(**kwargs) -> Logger  # synchronous, returns self

Adds key/value pairs to the bound context for the current task/thread. Bound fields are merged into all subsequent log calls until removed. Returns the logger instance for method chaining.

Example (sync)

logger = get_logger()
logger.bind(request_id="req-123", user_id="user-456")
logger.info("Request started")
# Output will include request_id and user_id

Example (async)

async with runtime_async() as logger:
    logger.bind(job_id="job-9")
    await logger.info("Job queued")

unbind {#unbind}

logger.unbind(*keys) -> Logger

Remove specific keys from the bound context for the current task/thread. Returns the logger instance for method chaining.

Example

logger.bind(request_id="req-123", user_id="user-456", temp_flag=True)
logger.unbind("temp_flag", "user_id")
logger.info("Context now only has request_id")

clear_context {#clear_context}

logger.clear_context() -> None

Remove all bound context values for the current task/thread.

Example

logger.bind(request_id="req-123")
logger.info("With context")
logger.clear_context()
logger.info("Context cleared")

Inheritance across tasks

Context is stored in a ContextVar, so it flows into asyncio tasks spawned from the same parent context:

import asyncio
from fapilog import runtime_async

async def child(name, logger):
    await logger.info(f"{name} started")

async def main():
    async with runtime_async() as logger:
        logger.bind(request_id="req-123")
        await asyncio.gather(child("task1", logger), child("task2", logger))

asyncio.run(main())

Use context binding to keep correlation IDs and user/request data attached to every log call.