Skip to main content

cli loggging utilities

Project description

hotlog

Generalized logging utility for Python projects

Overview

hotlog provides a simple, flexible, and structured logging interface for Python applications and libraries. It wraps structlog and rich to offer:

  • Three-level verbosity system for controlling output detail
  • Rich colored output with YAML-formatted context
  • Live logging support for dynamic status updates (at default level)
  • Context-aware logging with prefix-based filtering (_verbose_, _debug_)
  • Unified API: from hotlog import get_logger, configure_logging
  • Works seamlessly in CLI tools, scripts, and libraries

Features

Three Verbosity Levels

  • Level 0 (default): Essential info only, supports live updates that disappear
  • Level 1 (-v): More context visible, includes _verbose_ prefixed keys
  • Level 2 (-vv): All debug info, includes _debug_ prefixed keys, no live updates

Prefix Filtering

Control which context appears at different verbosity levels by using key prefixes:

  • Regular keys (no prefix): Always shown at all levels
  • _verbose_key: Only shown at level 1 (-v) or 2 (-vv)
  • _debug_key: Only shown at level 2 (-vv)

The prefixes are automatically removed when displayed, so _verbose_source becomes source.

logger.info(
    "Processing dataset",
    records=1000,                    # Always shown
    _verbose_source="data.csv",      # Only at -v or -vv
    _debug_file_size="2.5MB"         # Only at -vv
)

No special configuration needed - just prefix your keys and hotlog handles the rest!

Custom Log Matchers

Configure custom formatting rules for specific log patterns using matchers. Matchers check if a log entry matches certain conditions and apply custom formatting.

Built-in Matchers

ToolMatch: Format tool execution logs (toolbelt style)

from hotlog import configure_logging, get_logger, ToolMatch

# Configure with ToolMatch
configure_logging(
    verbosity=0,
    matchers=[
        ToolMatch(event="executing", prefix="tb")
    ]
)
logger = get_logger(__name__)

# Automatically formats as: tb[ruff-format] => ruff format .
logger.info(
    "executing",
    command="ruff format .",
    tool="ruff-format",
    _verbose_files_changed=14
)

The ToolMatch matcher checks for:

  • Event name: "executing" (configurable)
  • Log level: "INFO" (configurable)
  • Required key: command
  • Optional key: tool (shows in brackets)

Customize the matcher:

ToolMatch(
    event="executing",      # Event name to match
    prefix="pkg",          # Prefix shown before tool name
    level="INFO",          # Log level to match
    command_key="command", # Key containing command
    tool_key="tool"        # Key containing tool name
)

Creating Custom Matchers

Extend LogMatcher to create your own formatting rules:

from hotlog import LogMatcher, configure_logging, get_logger
from structlog.typing import EventDict
from typing import Optional

class InstallMatch(LogMatcher):
    """Custom matcher for package installation logs."""
    
    def matches(self, level: str, event: str, event_dict: EventDict) -> bool:
        """Check if this log entry matches our pattern."""
        return (
            level == "INFO" and
            event == "installed" and
            "package" in event_dict
        )
    
    def format(self, level: str, event: str, event_dict: EventDict) -> Optional[str]:
        """Format matching log entries.
        
        Note: Extract and remove keys you use from event_dict.
        Return None to fall back to default formatting.
        """
        package = event_dict.pop("package")
        version = event_dict.pop("version", "unknown")
        
        return f'[green]✓[/green] Installed [bold]{package}[/bold] [dim](version {version})[/dim]'

# Use your custom matcher
configure_logging(
    verbosity=0,
    matchers=[
        InstallMatch(),
        ToolMatch(event="executing", prefix="pkg"),
    ]
)
logger = get_logger(__name__)

# This will use InstallMatch formatting
logger.info("installed", package="requests", version="2.31.0")

# This will use ToolMatch formatting
logger.info("executing", command="uv pip install requests", tool="uv")

# This will use default formatting
logger.info("Build completed")

Key points about custom matchers:

  • Matchers are checked in order - first match wins
  • Use event_dict.pop() to remove keys you've formatted
  • Return None to fall back to default formatting
  • Remaining context keys are shown as YAML below the message
  • Rich markup is supported in formatted strings

Rich Output

  • Colored log levels (INFO=blue, WARNING=yellow, ERROR=red, DEBUG=magenta)
  • YAML-formatted context for easy reading
  • Syntax highlighting for structured data
  • Clean output without log level prefixes (like uv) - set show_levels=True for traditional [INFO] style

Highlighting Important Information

Emphasize specific values in your messages using Rich markup or the highlight() helper:

from hotlog import get_logger, highlight

logger = get_logger(__name__)

# Option 1: Direct Rich markup
logger.info("Installed [bold]5 packages[/bold] in [bold]3ms[/bold]")

# Option 2: Using highlight() helper
logger.info(highlight("Downloaded {} in {}", "14 files", "2.5s"))
# Renders as: "Downloaded [bold]14 files[/bold] in [bold]2.5s[/bold]"

This is perfect for level 0 summaries where you want to emphasize key metrics while keeping the output clean.

Live Logging

Use the live_logging context manager for operations with progress updates (level 0 only):

with live_logging("Downloading..."):
    # Your operation here
    logger.info("Connected", host="example.com")

Usage

Basic Example

from hotlog import configure_logging, get_logger

# Configure logging (verbosity: 0, 1, or 2)
configure_logging(verbosity=0)
logger = get_logger(__name__)

# Log messages
logger.info("Starting process", task_id=123)
logger.info("Processing data", records=100, _verbose_source="db.sqlite")
logger.warning("Rate limit approaching", current=95, limit=100)

With Different Verbosity Levels

# Level 0: Only essential info
configure_logging(verbosity=0)
logger.info("Processing", items=10, _verbose_detail="xyz", _debug_internals="abc")
# Output: items=10 only

# Level 1: Include verbose context
configure_logging(verbosity=1)
logger.info("Processing", items=10, _verbose_detail="xyz", _debug_internals="abc")
# Output: items=10, detail="xyz"

# Level 2: Include all debug context
configure_logging(verbosity=2)
logger.info("Processing", items=10, _verbose_detail="xyz", _debug_internals="abc")
# Output: items=10, detail="xyz", internals="abc"

Live Logging Example

from hotlog import configure_logging, get_logger, live_logging
import time

configure_logging(verbosity=0)
logger = get_logger(__name__)

with live_logging("Downloading repository..."):
    time.sleep(1)
    logger.info("Connected to server")
    time.sleep(1)
    logger.info("Fetching metadata")
    
logger.info("Download completed")

CLI Integration

import argparse
from hotlog import configure_logging, get_logger

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)
args = parser.parse_args()

# Map -v/-vv to verbosity levels
configure_logging(verbosity=min(args.verbose, 2))
logger = get_logger(__name__)

Installation

# Install dependencies (adjust based on your package manager)
pip install structlog rich pyyaml

Why hotlog?

Hotlog standardizes logging across multiple projects and CLIs, making it easy to:

  • Provide consistent verbosity control
  • Display beautiful, readable logs
  • Handle live updates for better UX
  • Filter context based on user's needs
  • Customize log formatting with matchers

No more reinventing logging configuration for every project!

Examples

See the example_*.py files for more usage patterns:

  • example_quickstart.py - Comprehensive quick start guide
  • example_cli.py - Full CLI simulation
  • example_toolbelt.py - Tool execution logging with ToolMatch
  • example_custom_matcher.py - Creating custom matchers
  • example_highlight.py - Using highlight() and Rich markup
  • example_prefixes.py - Prefix filtering demonstration

Run examples with different verbosity levels:

python example_toolbelt.py      # Level 0 (default)
python example_toolbelt.py -v   # Level 1 (verbose)
python example_toolbelt.py -vv  # Level 2 (debug)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hotlog-0.0.3.tar.gz (12.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hotlog-0.0.3-py3-none-any.whl (16.8 kB view details)

Uploaded Python 3

File details

Details for the file hotlog-0.0.3.tar.gz.

File metadata

  • Download URL: hotlog-0.0.3.tar.gz
  • Upload date:
  • Size: 12.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.20

File hashes

Hashes for hotlog-0.0.3.tar.gz
Algorithm Hash digest
SHA256 98c1808f0d96cd2a095688faf614f0972eac4c8a64369e561a5c01f1fc044b0b
MD5 34b49af59b93e4637273ffd8c5dfb663
BLAKE2b-256 3b97385ffdb774451abfbbfbb85f736a62482edf349fd68446e6e262a84c069c

See more details on using hashes here.

File details

Details for the file hotlog-0.0.3-py3-none-any.whl.

File metadata

  • Download URL: hotlog-0.0.3-py3-none-any.whl
  • Upload date:
  • Size: 16.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.7.20

File hashes

Hashes for hotlog-0.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 998cf5d05434fda8185a2461d8b751d52e7266ea4a99bd6c1d068f50c50b2ec4
MD5 762eaafa75bbb3100cfb7eb78b26e911
BLAKE2b-256 8fee24daf355e9a01c67928f284f4995fc67b99c7be982cd75bfa1021d82ce2b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page