Skip to content

Handlers

Handler factories and formatters for log output. These utilities create pre-configured handlers for various output destinations.

Quick Reference

Python
from pylogshield.handlers import (
    create_console_handler,
    create_file_handler,
    create_rotating_file_handler,
    create_rich_handler,
    JsonFormatter
)
import logging
from pathlib import Path

# Console handler with JSON output
console = create_console_handler(logging.INFO, json_format=True)

# File handler
file_handler = create_file_handler(Path("app.log"), logging.DEBUG)

# Rotating file handler (5MB max, 3 backups)
rotating = create_rotating_file_handler(
    Path("app.log"),
    logging.INFO,
    max_bytes=5_000_000,
    backup_count=3
)

# Rich console handler (colorized output)
rich_handler = create_rich_handler(logging.DEBUG)

JsonFormatter

Format log records as structured JSON for log aggregation systems.

Output Format

JSON
{
    "timestamp": "2024-01-15T10:30:00.123+00:00",
    "host": "server-01",
    "logger": "my_app",
    "level": "INFO",
    "message": "User logged in",
    "extra": {
        "user_id": "12345"
    }
}

Basic Usage

Python
from pylogshield.handlers import JsonFormatter
import logging

# Create formatter
formatter = JsonFormatter()

# With pretty printing
formatter = JsonFormatter(indent=2)

# Without extra fields
formatter = JsonFormatter(include_extra=False)

# Apply to handler
handler = logging.StreamHandler()
handler.setFormatter(formatter)

ISO 8601 Timestamps

All timestamps are formatted in ISO 8601 format with millisecond precision and UTC timezone:

Python
# Example output:
# "2024-01-15T10:30:00.123+00:00"

Handler Factory Functions

create_console_handler

Create a console (stderr) handler:

Python
from pylogshield.handlers import create_console_handler
import logging

# Standard format
handler = create_console_handler(logging.INFO)

# JSON format
handler = create_console_handler(logging.INFO, json_format=True)

create_file_handler

Create a simple file handler:

Python
from pylogshield.handlers import create_file_handler
from pathlib import Path

# Standard format
handler = create_file_handler(Path("app.log"), logging.DEBUG)

# JSON format
handler = create_file_handler(
    Path("app.log"),
    logging.DEBUG,
    json_format=True
)

# Parent directories are created automatically
handler = create_file_handler(
    Path("/var/log/myapp/app.log"),
    logging.INFO
)

create_rotating_file_handler

Create a handler that rotates logs based on file size:

Python
from pylogshield.handlers import create_rotating_file_handler
from pathlib import Path

handler = create_rotating_file_handler(
    Path("app.log"),
    logging.INFO,
    max_bytes=5_000_000,  # 5 MB (default)
    backup_count=5,       # Keep 5 backups (default)
    json_format=False     # Standard format (default)
)

This creates files: - app.log (current) - app.log.1 (previous) - app.log.2 - ... up to app.log.5

create_rich_handler

Create a Rich console handler with colorized output:

Python
from pylogshield.handlers import create_rich_handler
import logging

handler = create_rich_handler(logging.DEBUG)

# Falls back to standard console handler if Rich is not installed

Rich handler features: - Colorized output by log level - Rich tracebacks for exceptions - Clean, formatted output

Custom Handler Setup

Adding Multiple Handlers

Python
import logging
from pathlib import Path
from pylogshield.handlers import (
    create_console_handler,
    create_rotating_file_handler
)

logger = logging.getLogger("my_app")
logger.setLevel(logging.DEBUG)

# Console: INFO and above
logger.addHandler(create_console_handler(logging.INFO))

# File: DEBUG and above, with rotation
logger.addHandler(create_rotating_file_handler(
    Path("debug.log"),
    logging.DEBUG,
    max_bytes=10_000_000,
    backup_count=10
))

JSON Logging for Production

Python
from pylogshield.handlers import create_console_handler, create_file_handler
from pathlib import Path
import logging

logger = logging.getLogger("production_app")

# JSON to stdout for container logs
logger.addHandler(create_console_handler(logging.INFO, json_format=True))

# JSON to file for log aggregation
logger.addHandler(create_file_handler(
    Path("/var/log/app/app.json"),
    logging.DEBUG,
    json_format=True
))

API Reference

handlers

CLASS DESCRIPTION
JsonFormatter

JSON formatter that emits a structured log envelope.

FUNCTION DESCRIPTION
create_console_handler

Create a console (stderr) handler with standard or JSON formatting.

create_file_handler

Create a simple file handler.

create_rotating_file_handler

Create a rotating file handler that rotates logs based on file size.

create_rich_handler

Create a Rich console handler with colorized output.

JsonFormatter(*, indent: Optional[int] = None, include_extra: bool = True)

Bases: Formatter

JSON formatter that emits a structured log envelope.

This formatter outputs log records as JSON objects with a consistent structure suitable for log aggregation systems like ELK, Splunk, etc.

PARAMETER DESCRIPTION

indent

Indentation level for JSON output. None for compact output (default).

TYPE: int or None DEFAULT: None

include_extra

Whether to include extra fields from LogRecord. Default is True.

TYPE: bool DEFAULT: True

ATTRIBUTE DESCRIPTION
indent

Indentation level for JSON output.

TYPE: int or None

include_extra

Whether to include extra fields from LogRecord.

TYPE: bool

hostname

The hostname of the machine generating logs.

TYPE: str

Examples:

Python Console Session
>>> formatter = JsonFormatter(indent=2)
>>> handler = logging.StreamHandler()
>>> handler.setFormatter(formatter)
METHOD DESCRIPTION
formatTime

Format the log record timestamp as ISO 8601 with timezone.

Source code in src/pylogshield/handlers.py
Python
def __init__(
    self, *, indent: Optional[int] = None, include_extra: bool = True
) -> None:
    super().__init__()
    self.indent = indent
    self.include_extra = include_extra
    try:
        self.hostname = socket.gethostname()
    except OSError:
        self.hostname = "unknown"

formatTime(record: logging.LogRecord, datefmt: Optional[str] = None) -> str

Format the log record timestamp as ISO 8601 with timezone.

PARAMETER DESCRIPTION
record

The log record to format.

TYPE: LogRecord

datefmt

Custom date format string. If None, uses ISO 8601 format.

TYPE: str or None DEFAULT: None

RETURNS DESCRIPTION
str

The formatted timestamp string in UTC timezone.

Source code in src/pylogshield/handlers.py
Python
def formatTime(
    self, record: logging.LogRecord, datefmt: Optional[str] = None
) -> str:
    """Format the log record timestamp as ISO 8601 with timezone.

    Parameters
    ----------
    record : logging.LogRecord
        The log record to format.
    datefmt : str or None, optional
        Custom date format string. If None, uses ISO 8601 format.

    Returns
    -------
    str
        The formatted timestamp string in UTC timezone.
    """
    dt = datetime.fromtimestamp(record.created, tz=timezone.utc)
    if datefmt:
        return dt.strftime(datefmt)
    return dt.isoformat(timespec="milliseconds")

create_console_handler(level: int, *, json_format: bool = False) -> logging.Handler

Create a console (stderr) handler with standard or JSON formatting.

PARAMETER DESCRIPTION

level

The logging level for the handler.

TYPE: int

json_format

Whether to use JSON formatting. Default is False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Handler

A configured StreamHandler instance.

Source code in src/pylogshield/handlers.py
Python
def create_console_handler(level: int, *, json_format: bool = False) -> logging.Handler:
    """Create a console (stderr) handler with standard or JSON formatting.

    Parameters
    ----------
    level : int
        The logging level for the handler.
    json_format : bool, optional
        Whether to use JSON formatting. Default is False.

    Returns
    -------
    logging.Handler
        A configured StreamHandler instance.
    """
    handler = logging.StreamHandler()
    handler.setLevel(level)
    handler.setFormatter(JsonFormatter() if json_format else _standard_formatter())
    return handler

create_file_handler(path: Path, level: int, *, json_format: bool = False) -> logging.Handler

Create a simple file handler.

PARAMETER DESCRIPTION

path

The path to the log file. Parent directories are created if needed.

TYPE: Path

level

The logging level for the handler.

TYPE: int

json_format

Whether to use JSON formatting. Default is False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Handler

A configured FileHandler instance.

Source code in src/pylogshield/handlers.py
Python
def create_file_handler(
    path: Path, level: int, *, json_format: bool = False
) -> logging.Handler:
    """Create a simple file handler.

    Parameters
    ----------
    path : Path
        The path to the log file. Parent directories are created if needed.
    level : int
        The logging level for the handler.
    json_format : bool, optional
        Whether to use JSON formatting. Default is False.

    Returns
    -------
    logging.Handler
        A configured FileHandler instance.
    """
    path.parent.mkdir(parents=True, exist_ok=True)
    handler = logging.FileHandler(path, encoding="utf-8")
    handler.setLevel(level)
    handler.setFormatter(JsonFormatter() if json_format else _standard_formatter())
    return handler

create_rotating_file_handler(path: Path, level: int, *, max_bytes: int = 5000000, backup_count: int = 5, json_format: bool = False) -> logging.Handler

Create a rotating file handler that rotates logs based on file size.

PARAMETER DESCRIPTION

path

The path to the log file. Parent directories are created if needed.

TYPE: Path

level

The logging level for the handler.

TYPE: int

max_bytes

Maximum file size in bytes before rotation. Default is 5,000,000.

TYPE: int DEFAULT: 5000000

backup_count

Number of backup files to keep. Default is 5.

TYPE: int DEFAULT: 5

json_format

Whether to use JSON formatting. Default is False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Handler

A configured RotatingFileHandler instance.

Source code in src/pylogshield/handlers.py
Python
def create_rotating_file_handler(
    path: Path,
    level: int,
    *,
    max_bytes: int = 5_000_000,
    backup_count: int = 5,
    json_format: bool = False,
) -> logging.Handler:
    """Create a rotating file handler that rotates logs based on file size.

    Parameters
    ----------
    path : Path
        The path to the log file. Parent directories are created if needed.
    level : int
        The logging level for the handler.
    max_bytes : int, optional
        Maximum file size in bytes before rotation. Default is 5,000,000.
    backup_count : int, optional
        Number of backup files to keep. Default is 5.
    json_format : bool, optional
        Whether to use JSON formatting. Default is False.

    Returns
    -------
    logging.Handler
        A configured RotatingFileHandler instance.
    """
    path.parent.mkdir(parents=True, exist_ok=True)
    handler = RotatingFileHandler(
        path, maxBytes=max_bytes, backupCount=backup_count, encoding="utf-8"
    )
    handler.setLevel(level)
    handler.setFormatter(JsonFormatter() if json_format else _standard_formatter())
    return handler

create_rich_handler(level: int) -> logging.Handler

Create a Rich console handler with colorized output.

Falls back to a standard console handler if Rich is not installed.

PARAMETER DESCRIPTION

level

The logging level for the handler.

TYPE: int

RETURNS DESCRIPTION
Handler

A RichHandler if Rich is available, otherwise a StreamHandler.

Source code in src/pylogshield/handlers.py
Python
def create_rich_handler(level: int) -> logging.Handler:
    """Create a Rich console handler with colorized output.

    Falls back to a standard console handler if Rich is not installed.

    Parameters
    ----------
    level : int
        The logging level for the handler.

    Returns
    -------
    logging.Handler
        A RichHandler if Rich is available, otherwise a StreamHandler.
    """
    if _HAS_RICH:
        h = RichHandler(
            rich_tracebacks=True,
            show_time=True,
            show_path=False,
            omit_repeated_times=False,
            log_time_format="[%H:%M:%S]",
        )
        h.setLevel(level)
        h.setFormatter(
            logging.Formatter("%(name)s  %(module)s:%(lineno)d  %(message)s")
        )
        return h
    return create_console_handler(level)