Skip to content
Edit this page

Context Binding

This example demonstrates how to use Logly's context binding features to add persistent and temporary context to your log messages, making them more informative and traceable.

Code Example

from logly import logger

# Configure logging
logger.configure(level="INFO")
logger.add("console")

# Create a bound logger with persistent context
request_logger = logger.bind(user_id=12345, session_id="abc-123", service="auth")

# All logs from this logger include the bound context
request_logger.info("User authentication started")
request_logger.info("Validating credentials")
request_logger.info("Password verification successful")

# Nested context with contextualize
with logger.contextualize(request_id="req-456", endpoint="/login"):
    logger.info("Processing login request")

    # This log inherits the contextualize context
    logger.info("User lookup completed")

    # You can nest contextualize blocks
    with logger.contextualize(operation="password_check"):
        logger.info("Checking password hash")
        logger.info("Hash verification passed")

    logger.info("Login successful")

# Context from contextualize is cleared after the block
logger.info("Authentication flow completed")

Expected Output

[INFO] User authentication started | user_id=12345 | session_id=abc-123 | service=auth
[INFO] Validating credentials | user_id=12345 | session_id=abc-123 | service=auth
[INFO] Password verification successful | user_id=12345 | session_id=abc-123 | service=auth
[INFO] Processing login request | request_id=req-456 | endpoint=/login
[INFO] User lookup completed | request_id=req-456 | endpoint=/login
[INFO] Checking password hash | request_id=req-456 | endpoint=/login | operation=password_check
[INFO] Hash verification passed | request_id=req-456 | endpoint=/login | operation=password_check
[INFO] Login successful | request_id=req-456 | endpoint=/login
[INFO] Authentication flow completed

What happens: - logger.bind() creates a new logger instance with persistent context (user_id, session_id, service) - logger.contextualize() adds temporary context for the duration of the with block - Context can be nested - inner blocks inherit outer context - After exiting a contextualize block, that context is removed - The bound logger keeps its context throughout its lifetime

Advanced Context Examples

Web Application Context

from flask import request, g
from logly import logger

def setup_request_logging():
    """Setup context for each web request"""
    logger.bind(
        request_id=request.headers.get('X-Request-ID', 'unknown'),
        user_agent=request.headers.get('User-Agent'),
        ip=request.remote_addr,
        method=request.method,
        path=request.path
    )

@app.before_request
def before_request():
    setup_request_logging()
    logger.info("Request started")

@app.after_request
def after_request(response):
    logger.info("Request completed", status=response.status_code, size=len(response.data))
    return response

Database Transaction Context

from logly import logger

def execute_transaction(user_id: int, operation: str):
    """Execute database transaction with context"""
    with logger.contextualize(user_id=user_id, operation=operation, transaction_id="tx-123"):
        logger.info("Starting transaction")

        try:
            # Database operations here
            logger.info("Executing SQL query", query="SELECT * FROM users")
            logger.info("Query completed", rows_affected=1)

            logger.info("Committing transaction")
            # commit logic

        except Exception as e:
            logger.error("Transaction failed", error=str(e))
            raise

Multi-tenant Application

from logly import logger

class TenantContext:
    def __init__(self, tenant_id: str, user_id: str):
        self.tenant_id = tenant_id
        self.user_id = user_id

    def __enter__(self):
        logger.bind(tenant_id=self.tenant_id, user_id=self.user_id)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        logger.unbind("tenant_id", "user_id")

def process_tenant_request(tenant_id: str, user_id: str, data: dict):
    with TenantContext(tenant_id, user_id):
        logger.info("Processing tenant request", data_size=len(str(data)))

        # Process data
        logger.info("Validation completed")
        logger.info("Data processing completed")

        return {"status": "success"}

Context Management Methods

Persistent Context

# Add persistent context
logger.bind(key="value", key2="value2")

# Remove specific keys
logger.unbind("key")

# Clear all context
logger.unbind_all()

Temporary Context

# Context for single log
logger.info("Message", extra={"temp_key": "temp_value"})

# Context for code block
with logger.contextualize(temp_key="temp_value"):
    logger.info("This log has temp context")
    logger.info("This one too")

# After block, context is gone
logger.info("Back to normal context")

Key Features Demonstrated

  • Persistent context: Context that applies to all subsequent logs
  • Temporary context: Context for specific operations or code blocks
  • Nested context: Hierarchical context inheritance
  • Automatic formatting: Context automatically included in log format
  • Thread safety: Context is isolated per thread