CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-structlog

Structured logging for Python that emphasizes simplicity, power, and performance

Overview
Eval results
Files

bound-loggers.mddocs/

Bound Logger Classes

Immutable context-carrying logger classes that provide the core structlog API. Bound loggers maintain context data and delegate logging operations to wrapped loggers while supporting context binding, unbinding, and transformation operations.

Capabilities

Base Bound Logger

Base class for all bound loggers providing core context manipulation and event processing functionality.

class BoundLoggerBase:
    """
    Base class for immutable context carriers.
    
    Provides core functionality for context binding, unbinding, and event processing.
    All bound logger implementations inherit from this class.
    """
    
    def __init__(self, logger, processors, context): ...
    
    def bind(self, **new_values) -> Self:
        """
        Return new bound logger with additional context values.

        Args:
            **new_values: Key-value pairs to add to the context

        Returns:
            New bound logger instance with merged context
        """
    
    def unbind(self, *keys) -> Self:
        """
        Return new bound logger with specified keys removed from context.

        Args:
            *keys: Context keys to remove

        Returns:
            New bound logger instance with keys removed
            
        Raises:
            KeyError: If any key is not found in context
        """
    
    def try_unbind(self, *keys) -> Self:
        """
        Return new bound logger with specified keys removed, ignoring missing keys.

        Args:
            *keys: Context keys to remove

        Returns:
            New bound logger instance with existing keys removed
        """
    
    def new(self, **new_values) -> Self:
        """
        Return new bound logger with cleared context and new values.

        Args:
            **new_values: Key-value pairs for the new context

        Returns:
            New bound logger instance with only the specified context
        """
    
    def _process_event(self, method_name, event, event_kw) -> tuple[Sequence[Any], Mapping[str, Any]]:
        """Process event through processor chain (protected method)."""
    
    def _proxy_to_logger(self, method_name, event=None, **event_kw) -> Any:
        """Proxy method call to wrapped logger (protected method)."""

Generic Bound Logger

Generic bound logger that can wrap any logger and provides dynamic method delegation.

class BoundLogger(BoundLoggerBase):
    """
    Generic bound logger that can wrap anything.
    
    Uses dynamic method delegation to forward all method calls
    to the wrapped logger after processing through the processor chain.
    """

Context Utilities

Functions for working with bound logger contexts.

def get_context(bound_logger) -> Context:
    """
    Return the context dictionary from a bound logger.

    Args:
        bound_logger: Bound logger instance

    Returns:
        dict: Copy of the logger's context
    """

Usage Examples

Basic Context Binding

import structlog

structlog.configure(
    processors=[structlog.processors.JSONRenderer()],
    wrapper_class=structlog.BoundLogger,
)

logger = structlog.get_logger()

# Bind context values
user_logger = logger.bind(user_id=123, username="alice")
user_logger.info("User logged in")

# Bind additional context
session_logger = user_logger.bind(session_id="abc-def", ip="192.168.1.1")
session_logger.info("Session created")

# Original logger is unchanged
logger.info("System message")  # No user context

Context Unbinding

import structlog

logger = structlog.get_logger()
rich_logger = logger.bind(
    user_id=123,
    session_id="abc-def",
    request_id="req-456",
    debug_info="temp"
)

# Remove specific keys
clean_logger = rich_logger.unbind("debug_info")
clean_logger.info("Cleaned up")  # No debug_info

# Remove multiple keys
minimal_logger = rich_logger.unbind("debug_info", "request_id")
minimal_logger.info("Minimal context")  # Only user_id and session_id

# try_unbind ignores missing keys
safe_logger = rich_logger.try_unbind("missing_key", "debug_info")
safe_logger.info("Safe unbind")  # No error for missing_key

Context Replacement

import structlog

logger = structlog.get_logger()
request_logger = logger.bind(
    user_id=123,
    session_id="old-session",
    request_id="req-1"
)

# Clear all context and start fresh
new_request_logger = request_logger.new(
    user_id=456,
    request_id="req-2",
    endpoint="/api/orders"
)

new_request_logger.info("New request started")  # Only new context

Working with Context

import structlog

logger = structlog.get_logger()
context_logger = logger.bind(service="auth", version="1.2.3")

# Get the current context
context = structlog.get_context(context_logger)
print(context)  # {'service': 'auth', 'version': '1.2.3'}

# Use context for conditional logic
if context.get("service") == "auth":
    enhanced_logger = context_logger.bind(auth_enabled=True)
    enhanced_logger.info("Authentication service ready")

Chaining Context Operations

import structlog

logger = structlog.get_logger()

# Chain multiple context operations
request_logger = (logger
    .bind(request_id="req-789")
    .bind(user_id=123, ip="10.0.0.1")
    .unbind("ip")  # Remove IP for privacy
    .bind(anonymized=True)
)

request_logger.info("Request processed")

Custom Context Classes

import structlog
from collections import UserDict

class CustomContext(UserDict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.access_count = 0
    
    def __getitem__(self, key):
        self.access_count += 1
        return super().__getitem__(key)

structlog.configure(
    processors=[structlog.processors.JSONRenderer()],
    wrapper_class=structlog.BoundLogger,
    context_class=CustomContext,
)

logger = structlog.get_logger()
tracked_logger = logger.bind(user_id=123)
tracked_logger.info("Tracking access")

Error Handling in Context Operations

import structlog

logger = structlog.get_logger()
context_logger = logger.bind(user_id=123, session_id="abc")

try:
    # This will raise KeyError
    broken_logger = context_logger.unbind("missing_key")
except KeyError:
    # Use try_unbind instead
    safe_logger = context_logger.try_unbind("missing_key")
    safe_logger.info("Handled missing key gracefully")

# Alternative: check context first
context = structlog.get_context(context_logger)
if "session_id" in context:
    clean_logger = context_logger.unbind("session_id")
    clean_logger.info("Session cleaned up")

Install with Tessl CLI

npx tessl i tessl/pypi-structlog

docs

bound-loggers.md

configuration.md

context-management.md

development-tools.md

exception-handling.md

index.md

logger-creation.md

output-loggers.md

processors.md

stdlib-integration.md

testing.md

tile.json