Skip to main content

Utilities for logging, assertions and custom exceptions

Project description

Logguard

Structured logging and assertion utilities for Python

Logguard provides a powerful yet simple logging configuration system with rich formatting support, automatic file rotation, and assertion utilities that capture context automatically.

Features

  • 🔧 Easy Configuration: Set up logging in one line with AppLogger
  • 📝 File Rotation: Automatic log rotation with configurable size and backup count
  • 🎨 Rich Console Output: Beautiful console logs with Rich support
  • 📊 JSON Logging: Optional structured JSON output for log aggregation systems
  • ✅ Smart Assertions: ASSERT and enforce with automatic source capture and logging
  • 🎯 Semantic Exceptions: Clear exception hierarchy (ValidationError, ConfigurationError, etc.)
  • ⚡ Fast Startup: Lazy imports for minimal performance impact
  • 🔇 Library Silencing: Automatically suppresses noisy third-party library logs

Installation

pip install py-logguard

For development with optional dependencies:

pip install -e ".[dev]"

For JSON logging support:

pip install -e ".[json]"

Quick Start

Basic Logging

from logguard import AppLogger

# Configure logging (optional - auto-configures on first use)
AppLogger.setup(
    log_file="logs/app.log",
    console_level="INFO",
    file_level="DEBUG"
)

# Get a logger
logger = AppLogger.get_logger(__name__)

# Use it
logger.info("Application started")
logger.debug("Debug information")
logger.warning("Warning message")
logger.error("Error occurred")

Assertions with Context

from logguard import ASSERT, AppLogger
from logguard.exceptions import ValidationError

logger = AppLogger().get_logger("validation_example")

def process_user(name: str, age: int) -> dict:
    # ASSERT captures context automatically:
    # - Expression from source code
    # - Filename, line number, function name
    # - Local variables (optional)
    ASSERT(bool(name), "Name cannot be empty")
    ASSERT(len(name) >= 2, "Name must have at least 2 characters")
    ASSERT(age >= 0, "Age cannot be negative")
    ASSERT(age <= 150, "Age seems unrealistic")

    return {"name": name, "age": age, "valid": True}

# Assertions raise ValidationError on failure
try:
    process_user("", 25)
except ValidationError as e:
    logger.error(f"Validation failed: {e}")

Manual Assertions with enforce

For cases where you need explicit control over assertion parameters, use enforce:

from logguard import enforce

# enforce() requires you to provide all context manually
enforce(
    condition=value > 0,
    message="Value must be positive",
    expression="value > 0",
    filename=__file__,
    line=10,
    function="my_function",
    extra={"value": value}
)

Custom Exceptions

from logguard.exceptions import (
    ValidationError,
    ConfigurationError,
    ResourceNotFoundError,
    AuthenticationError,
    ExternalServiceError
)

# Use semantic exceptions for clearer error handling
def load_config(path: str):
    if not os.path.exists(path):
        raise ConfigurationError(f"Config file not found: {path}")

# Catch resource errors
try:
    get_user(user_id)
except ResourceNotFoundError as e:
    logger.error(f"User not found: {e}")

# External service error handling
try:
    # Your code that calls an external API
    api_call(...)
except ExternalServiceError as e:
    logger.error(f"Service error: {e}")

Advanced Usage

Logger Configuration Options

AppLogger.setup(
    log_file="logs/myapp.log",      # Path to log file
    console_level="INFO",             # Console log level
    file_level="DEBUG",               # File log level
    json_logs=False,                  # Enable JSON formatting
    max_bytes=5_000_000,              # Max file size (5MB)
    backup_count=3,                   # Number of backup files
    force=False                       # Force reconfiguration
)

Dynamic Log Level Changes

# Change log level at runtime
AppLogger.set_level("DEBUG", handler_type="console")
AppLogger.set_level("WARNING", handler_type="file")
AppLogger.set_level("INFO", handler_type="all")

Auto-detection of Logger Name

# Automatically uses the module name
logger = AppLogger.get_logger()  # Uses __name__ of calling module

# Or explicitly specify
logger = AppLogger.get_logger("myapp.services")

JSON Logging for Production

import os

from logguard.logger import AppLogger

# Enable JSON logs via environment variable
os.environ["JSON_LOGS"] = "true"

# Or directly in setup
AppLogger.setup(json_logs=True)

logger = AppLogger().get_logger("example")
logger.info("This is an info message with JSON formatting!")
logger.error("This is an error message with JSON formatting!")

# Installed via: pip install -e ".[json]" or pip install python-json-logger>=2.0

Exception Hierarchy

Logguard provides a semantic exception hierarchy for clearer error handling:

  • AppBaseError - Base exception for all logguard errors
  • ValidationError - Data validation failures (raised by ASSERT)
  • ConfigurationError - Configuration or setup issues
  • ResourceError - Base for resource-related errors
    • ResourceNotFoundError - Requested resource doesn't exist
    • AuthenticationError - Authentication/authorization failed
    • PermissionError - Permission denied
  • OperationError - Business operation failures
  • ExternalServiceError - External service failures
    • RateLimitError - Rate limit exceeded

API Reference

AppLogger

Setup Method:

AppLogger.setup(
    log_file: str | None = None,
    console_level: str = "INFO",
    file_level: str = "DEBUG", 
    json_logs: bool = False,
    max_bytes: int = 5_000_000,
    backup_count: int = 3,
    force: bool = False
) -> None

Main Methods:

  • setup(...) - Configure the logging system
  • get_logger(name: str | None = None) - Get or create a logger instance
  • set_level(level: str, handler_type: str = "all") - Change log level dynamically
  • reset() - Reset logging configuration (useful for testing)

Assertions

Basic Assertions:

  • ASSERT(condition, message="") - Raise ValidationError if condition is False (auto-captures expression, file, line)
  • enforce(condition, message="", ...) - Explicit assertion (requires manual parameters: expression, filename, line, function)

Specialized Assertions:

  • ASSERT_TYPE(value, expected_type, message="") - Assert value is of expected type
  • ASSERT_NOT_NONE(value, message="") - Assert value is not None
  • ASSERT_NOT_EMPTY(value, message="") - Assert string/collection is not empty
  • ASSERT_IN(value, collection, message="") - Assert value is in collection
  • ASSERT_RANGE(value, min_val, max_val, message="") - Assert value is in range
  • ASSERT_EQUALS(actual, expected, message="") - Assert values are equal

Configuration:

  • set_failure_handler(handler) - Custom handler for assertion failures

Exceptions

All exceptions inherit from AppBaseError and include:

  • message - Description of the error
  • context - Additional context data (dict)
  • status_code - Suggested HTTP status code
  • to_dict() - Serialize exception to dictionary

Exception Classes:

AppBaseError (base for all)
├── ConfigurationError
│   └── MissingConfigError
├── ValidationError
│   └── DataFormatError
├── ResourceError
│   ├── ResourceNotFoundError
│   ├── AuthenticationError
│   └── PermissionError (custom exception - see note below)
├── OperationError
│   ├── RetryableError
│   └── FatalOperationError
└── ExternalServiceError
    └── RateLimitError

Note on PermissionError: Logguard provides a custom PermissionError exception for application-level permission errors. This is distinct from Python's built-in PermissionError (used for OS-level errors). Always import explicitly from logguard to use this exception.

Usage Examples:

# Configuration errors
raise ConfigurationError("Invalid config", file_path="config.json")
raise MissingConfigError("DATABASE_URL", source=".env")

# Validation errors
raise ValidationError("Invalid input", field="email")
raise DataFormatError("Malformed JSON")

# Resource errors
raise ResourceNotFoundError("User", identifier=123)
raise AuthenticationError("Invalid credentials")
raise PermissionError("Access denied")

# Operation errors
raise RetryableError("Network timeout", retry_after=5)
raise FatalOperationError("Critical failure")

# External service errors
raise ExternalServiceError("API", "Service unavailable")
raise RateLimitError("GitHub", reset_time=1234567890)

Examples

Check the examples/ directory for complete examples:

  • basic_usage.py - Basic logging and assertions
  • advanced_asserts.py - Advanced assertion patterns
  • test_improvements.py - Using logguard in tests
  • rich_exceptions_demo.py - Rich-formatted exceptions & logger exceptions in a simple banking system simulator

Development

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=logguard --cov-report=html

# Format code (use Ruff formatter)
ruff format .

# Auto-fix lintable issues
ruff check --fix .

# Type checking
mypy logguard/

# Lint
ruff check .

Requirements

  • Python 3.9+
  • Optional: rich for beautiful console output
  • Optional: python-json-logger for JSON formatting

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

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

py_logguard-0.1.1.tar.gz (38.8 kB view details)

Uploaded Source

Built Distribution

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

py_logguard-0.1.1-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

Details for the file py_logguard-0.1.1.tar.gz.

File metadata

  • Download URL: py_logguard-0.1.1.tar.gz
  • Upload date:
  • Size: 38.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for py_logguard-0.1.1.tar.gz
Algorithm Hash digest
SHA256 921716b1ca9a9b03eaaacdcb87e7eca9101305f86326d4f1c3077ea3ff861d35
MD5 5603cf3e51403d5c76708eb51683d66b
BLAKE2b-256 251875739366df84a3b437fdeb352284c1f9233278723265f0414e5a39194eea

See more details on using hashes here.

File details

Details for the file py_logguard-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: py_logguard-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 19.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for py_logguard-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 de39e624e1df95004cb88092f3fee9e31cf28693914f4568d194e0392139adf0
MD5 236a07dc4625c60e99ae47093d4af852
BLAKE2b-256 cc24d2327babea8701d8bac43ecf50edbeb3b5e89eeb09b81d343a7f616434ff

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