CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-mkdocstrings

Automatic documentation from sources, for MkDocs.

Pending
Overview
Eval results
Files

logging-system.mddocs/

Logging System

Specialized logging system designed for template environments and debugging mkdocstrings processing. The logging system provides enhanced logger adapters, template-friendly logging interfaces, and utility functions for debugging documentation generation.

Capabilities

Logger Adapter

Enhanced logger adapter with message prefixes and once-only logging support for cleaner log output.

class LoggerAdapter(logging.LoggerAdapter):
    """Logger adapter with prefix and once-only logging support."""
    
    def __init__(self, prefix: str, logger: logging.Logger) -> None:
        """
        Initialize adapter with prefix.
        
        Args:
            prefix: Message prefix string
            logger: Base logger instance
        """
    
    def process(
        self,
        msg: str,
        kwargs: MutableMapping[str, Any]
    ) -> tuple[str, Any]:
        """
        Process log message and add prefix.
        
        Args:
            msg: Log message
            kwargs: Logging keyword arguments
            
        Returns:
            Tuple of processed message and kwargs
        """
    
    def log(
        self,
        level: int,
        msg: object,
        *args: object,
        **kwargs: object
    ) -> None:
        """
        Log message with enhanced functionality.
        
        Args:
            level: Logging level
            msg: Message to log
            *args: Message arguments
            **kwargs: Logging options
        """
    
    prefix: str
    """Message prefix string."""

Usage Examples:

Create logger with prefix:

import logging
from mkdocstrings import LoggerAdapter

# Create base logger
base_logger = logging.getLogger("mkdocstrings.myhandler")

# Create adapter with prefix
logger = LoggerAdapter("MyHandler", base_logger)

# Log messages with automatic prefix
logger.info("Processing module")       # Logs: "[MyHandler] Processing module"
logger.error("Failed to parse")        # Logs: "[MyHandler] Failed to parse"
logger.debug("Debug information")      # Logs: "[MyHandler] Debug information"

Handler integration:

class MyHandler(BaseHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Create logger with handler-specific prefix
        base_logger = logging.getLogger(f"mkdocstrings.{self.name}")
        self.logger = LoggerAdapter(f"{self.name.title()}Handler", base_logger)
    
    def collect(self, identifier: str, options: HandlerOptions) -> CollectorItem:
        self.logger.info(f"Collecting documentation for {identifier}")
        
        try:
            data = self._do_collection(identifier)
            self.logger.debug(f"Successfully collected {len(data.members)} members")
            return data
        except Exception as e:
            self.logger.error(f"Collection failed for {identifier}: {e}")
            raise

Template Logger

Logger wrapper designed for use within Jinja2 templates, providing template-friendly logging methods.

class TemplateLogger:
    """Logger wrapper for use in Jinja templates."""
    
    def __init__(self, logger: LoggerAdapter) -> None:
        """
        Initialize with logger adapter.
        
        Args:
            logger: LoggerAdapter instance
        """
    
    debug: Callable
    """Log DEBUG level messages."""
    
    info: Callable
    """Log INFO level messages."""
    
    warning: Callable
    """Log WARNING level messages."""
    
    error: Callable
    """Log ERROR level messages."""
    
    critical: Callable
    """Log CRITICAL level messages."""

Usage Examples:

Use in templates:

from mkdocstrings import TemplateLogger, LoggerAdapter

# Create template logger
base_logger = logging.getLogger("mkdocstrings.template")
adapter = LoggerAdapter("Template", base_logger)
template_logger = TemplateLogger(adapter)

# Make available in template context
template_globals = {
    "logger": template_logger,
    "data": data
}

Template usage:

{# In Jinja2 template #}
{% if data.deprecated %}
  {{ logger.warning("Rendering deprecated item: " + data.name) }}
{% endif %}

{% if not data.docstring %}
  {{ logger.info("No docstring found for " + data.name) }}
{% endif %}

{# Log debug information #}
{{ logger.debug("Rendering " + data.type + " with " + data.members|length|string + " members") }}

Handler template integration:

def render(self, data: CollectorItem, options: HandlerOptions, *, locale: str | None = None) -> str:
    # Create template logger
    template_logger = get_template_logger(self.name)
    
    # Render template with logger
    template = self.env.get_template("handler.html")
    return template.render(
        data=data,
        options=options,
        logger=template_logger
    )

Utility Functions

Helper functions for creating and managing loggers in different contexts.

def get_logger(name: str) -> LoggerAdapter:
    """
    Return a pre-configured logger for MkDocs.
    
    Args:
        name: Logger name
        
    Returns:
        LoggerAdapter instance
    """

def get_template_logger(handler_name: str | None = None) -> TemplateLogger:
    """
    Return a logger for use in templates.
    
    Args:
        handler_name: Optional handler name for prefix
        
    Returns:
        TemplateLogger instance
    """

def get_template_logger_function(logger_func: Callable) -> Callable:
    """
    Create wrapper function for template logging.
    
    Args:
        logger_func: Logger function to wrap
        
    Returns:
        Wrapped logger function
    """

def get_template_path(context: Context) -> str:
    """
    Return path to template using given context.
    
    Args:
        context: Jinja2 template context
        
    Returns:
        Template path string
    """

Usage Examples:

Get configured logger:

from mkdocstrings import get_logger

# Get logger for specific component
logger = get_logger("mkdocstrings.python")

logger.info("Python handler initialized")
logger.debug("Loading configuration")

Get template logger:

from mkdocstrings import get_template_logger

# Get template logger for handler
template_logger = get_template_logger("python")

# Use in template rendering
template_context = {
    "logger": template_logger,
    "data": data,
    "options": options
}

Template path debugging:

from mkdocstrings import get_template_path

# In template rendering function
def render_template(self, template_name: str, **context):
    template = self.env.get_template(template_name)
    
    # Log template path for debugging
    if template.environment.globals.get("logger"):
        template_path = get_template_path(template.new_context())
        template.environment.globals["logger"].debug(f"Rendering template: {template_path}")
    
    return template.render(**context)

Integration Patterns

Handler Logging

Integrate logging throughout handler lifecycle:

class MyHandler(BaseHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        
        # Set up handler logger
        self.logger = get_logger(f"mkdocstrings.{self.name}")
        self.logger.info(f"Initialized {self.name} handler")
    
    def collect(self, identifier: str, options: HandlerOptions) -> CollectorItem:
        self.logger.debug(f"Collecting {identifier}")
        
        try:
            # Collection logic
            data = self._parse_identifier(identifier)
            self.logger.info(f"Collected {data.type} {data.name} with {len(data.members)} members")
            return data
            
        except ImportError as e:
            self.logger.error(f"Import failed for {identifier}: {e}")
            raise CollectionError(f"Could not import {identifier}")
        
        except Exception as e:
            self.logger.exception(f"Unexpected error collecting {identifier}")
            raise
    
    def render(self, data: CollectorItem, options: HandlerOptions, *, locale: str | None = None) -> str:
        self.logger.debug(f"Rendering {data.name}")
        
        # Create template logger
        template_logger = get_template_logger(self.name)
        
        try:
            html = self.render_template("handler.html", 
                data=data, 
                options=options,
                logger=template_logger
            )
            
            self.logger.debug(f"Rendered {len(html)} characters for {data.name}")
            return html
            
        except Exception as e:
            self.logger.error(f"Rendering failed for {data.name}: {e}")
            raise

Plugin Logging

Plugin-level logging for configuration and lifecycle events:

class MkdocstringsPlugin(BasePlugin):
    def __init__(self):
        super().__init__()
        self.logger = get_logger("mkdocstrings.plugin")
    
    def on_config(self, config: MkDocsConfig) -> MkDocsConfig | None:
        self.logger.info("Configuring mkdocstrings plugin")
        
        # Log configuration details
        if self.config.get("handlers"):
            handler_names = list(self.config["handlers"].keys())
            self.logger.info(f"Configured handlers: {', '.join(handler_names)}")
        
        self.logger.debug(f"Default handler: {self.config['default_handler']}")
        
        if self.config.get("custom_templates"):
            self.logger.info(f"Using custom templates from: {self.config['custom_templates']}")
        
        return config
    
    def on_post_build(self, config: MkDocsConfig, **kwargs):
        self.logger.info("mkdocstrings plugin build completed")
        
        # Log inventory statistics
        if hasattr(self, "handlers") and self.handlers.inventory:
            item_count = len(self.handlers.inventory)
            self.logger.info(f"Generated inventory with {item_count} items")

Template Error Reporting

Enhanced error reporting in templates:

{# Template: handler.html #}
{% set template_logger = get_template_logger("python") %}

{% if not data %}
  {{ template_logger.error("No data provided to template") }}
  <div class="error">No documentation data available</div>
{% else %}
  
  {% if not data.name %}
    {{ template_logger.warning("Data missing name attribute") }}
    <div class="warning">Documentation object missing name</div>
  {% endif %}
  
  {% for member in data.members %}
    {% if not member.signature %}
      {{ template_logger.debug("Member " + member.name + " has no signature") }}
    {% endif %}
  {% endfor %}
  
{% endif %}

Debug Mode

Enhanced debugging with verbose logging:

def enable_debug_logging():
    """Enable verbose debug logging for troubleshooting."""
    import logging
    
    # Set debug level for all mkdocstrings loggers
    logging.getLogger("mkdocstrings").setLevel(logging.DEBUG)
    
    # Create debug file handler
    debug_handler = logging.FileHandler("mkdocstrings_debug.log")
    debug_handler.setLevel(logging.DEBUG)
    
    # Format with detailed information
    formatter = logging.Formatter(
        "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    )
    debug_handler.setFormatter(formatter)
    
    # Add to root mkdocstrings logger
    logging.getLogger("mkdocstrings").addHandler(debug_handler)

# Usage
if debug_mode:
    enable_debug_logging()

This logging system provides comprehensive debugging capabilities while maintaining clean, informative output for normal operation.

Install with Tessl CLI

npx tessl i tessl/pypi-mkdocstrings

docs

handler-system.md

index.md

inventory-system.md

logging-system.md

markdown-processing.md

plugin-integration.md

rendering-system.md

tile.json