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:
ASSERTandenforcewith 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 errorsValidationError- Data validation failures (raised by ASSERT)ConfigurationError- Configuration or setup issuesResourceError- Base for resource-related errorsResourceNotFoundError- Requested resource doesn't existAuthenticationError- Authentication/authorization failedPermissionError- Permission denied
OperationError- Business operation failuresExternalServiceError- External service failuresRateLimitError- 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 systemget_logger(name: str | None = None)- Get or create a logger instanceset_level(level: str, handler_type: str = "all")- Change log level dynamicallyreset()- Reset logging configuration (useful for testing)
Assertions
Basic Assertions:
ASSERT(condition, message="")- RaiseValidationErrorif 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 typeASSERT_NOT_NONE(value, message="")- Assert value is not NoneASSERT_NOT_EMPTY(value, message="")- Assert string/collection is not emptyASSERT_IN(value, collection, message="")- Assert value is in collectionASSERT_RANGE(value, min_val, max_val, message="")- Assert value is in rangeASSERT_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 errorcontext- Additional context data (dict)status_code- Suggested HTTP status codeto_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 assertionsadvanced_asserts.py- Advanced assertion patternstest_improvements.py- Using logguard in testsrich_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:
richfor beautiful console output - Optional:
python-json-loggerfor 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
921716b1ca9a9b03eaaacdcb87e7eca9101305f86326d4f1c3077ea3ff861d35
|
|
| MD5 |
5603cf3e51403d5c76708eb51683d66b
|
|
| BLAKE2b-256 |
251875739366df84a3b437fdeb352284c1f9233278723265f0414e5a39194eea
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de39e624e1df95004cb88092f3fee9e31cf28693914f4568d194e0392139adf0
|
|
| MD5 |
236a07dc4625c60e99ae47093d4af852
|
|
| BLAKE2b-256 |
cc24d2327babea8701d8bac43ecf50edbeb3b5e89eeb09b81d343a7f616434ff
|