Logguard
Logguard is a lightweight logging and assertion library designed to make it easy to capture rich context and structured logs in Python applications. It provides a simple API for logging with automatic source capture, flexible configuration, and a semantic exception hierarchy.
It is built on top of the logging and rich libraries for enhanced logging capabilities.
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
- Environment-Aware Assertions:
CHECK,ASSERT,ENSURE,VERIFYwith context - Specialized Helpers:
ASSERT_TYPE,ASSERT_IN_RANGE,ASSERT_NOT_NULL, etc. - Semantic Exceptions: Clear exception hierarchy (
ValidationError,AssertFailure, etc.) - Fast Startup: Lazy imports for minimal performance impact
- Library Silencing: Automatically suppresses noisy third-party library logs
Installation
Install with pip or your favorite PyPI package manager.
python -m pip install py-logguard
For development with optional dependencies:
python -m pip install py-logguard[dev]
For JSON logging support:
python -m pip install py-logguard[json]
Quick Start
Logging
Logguard provides a simple way to configure logging with sensible defaults. Just call setup() once and you're ready to go.
from logguard import AppLogger
AppLogger.setup(log_file="logs/app.log", console_level="INFO")
logger = AppLogger.get_logger(__name__)
logger.info("Application started")
logger.debug("Debug info")
logger.warning("Warning")
logger.error("Error occurred")
Logging will output to both console and file, with automatic rotation when files get too large.
Assertions
Logguard provides environment-aware assertions that adapt their behavior based on APP_ENV:
| Assertion | Development | Production | Use Case |
|---|---|---|---|
CHECK |
Raises | Raises | Critical invariants |
ASSERT |
Raises | Ignored | Debug checks |
ENSURE |
Raises | Logs | Preconditions |
VERIFY |
Raises | Logs | Postconditions |
from logguard import CHECK, ASSERT, ENSURE, VERIFY
# CHECK: Always raises - use for critical invariants
CHECK(config is not None, "Configuration required", component="auth")
# ASSERT: Raises in dev, ignored in prod - use for debugging
ASSERT(age > 0, "Age must be positive", age=age)
# ENSURE: Raises in dev, logs in prod - use for preconditions
def process_order(order):
ENSURE(order.is_valid(), "Invalid order", order_id=order.id)
# VERIFY: Raises in dev, logs in prod - use for postconditions
result = calculate_total(items)
VERIFY(result >= 0, "Total cannot be negative", result=result)
Configure environment via APP_ENV variable:
- Development:
dev,development,local,test - Production:
prod,production
Specialized Assertions
Logguard includes helpers for common validation patterns:
from logguard import (
ASSERT_NOT_NULL,
ASSERT_TYPE,
ASSERT_IN_RANGE,
ASSERT_EQUALS,
ASSERT_IN,
ASSERT_NOT_EMPTY,
ASSERT_GREATER,
ASSERT_LESS,
)
# Null checks
ASSERT_NOT_NULL(user, "User is required")
# Type checking
ASSERT_TYPE(config, dict, "Expected dictionary")
# Range validation (inclusive)
ASSERT_IN_RANGE(percentage, 0, 100, "Invalid percentage")
# Equality
ASSERT_EQUALS(response.status, 200, "Expected success")
# Membership
ASSERT_IN(status, ["pending", "active"], "Invalid status")
# Non-empty
ASSERT_NOT_EMPTY(items, "Items list cannot be empty")
# Comparisons
ASSERT_GREATER(balance, 0, "Balance must be positive")
ASSERT_LESS(retry_count, max_retries, "Too many retries")
Each helper raises a specific exception type (NullError, TypeErrorAssert, RangeError, etc.) for precise error handling.
Custom Exceptions
Logguard provides a semantic exception hierarchy for clearer error handling:
from logguard import (
LogGuardError,
ValidationError,
AssertFailure,
NullError,
RangeError,
ConfigurationError,
ResourceNotFoundError,
ForbiddenError,
)
# All exceptions include rich context
try:
raise ValidationError("Invalid email", context={"field": "email", "value": "bad@"})
except LogGuardError as e:
print(f"Error: {e}")
print(f"Details: {e.to_dict()}")
# {'type': 'ValidationError', 'message': 'Invalid email', 'context': {'field': 'email', 'value': 'bad@'}}
# Catch specific assertion failures
try:
ASSERT_IN_RANGE(age, 0, 150)
except RangeError as e:
handle_invalid_age(e.context)
# Resource errors
raise ResourceNotFoundError("User", identifier=123)
raise ForbiddenError("Access denied", user_id=456)
Exception Hierarchy:
LogGuardError
├── ConfigurationError
│ └── MissingConfigError
├── ValidationError
│ └── AssertFailure
│ ├── NullError
│ ├── RangeError
│ ├── TypeErrorAssert
│ ├── EmptyError
│ ├── EqualsError
│ ├── ComparisonError
│ └── MembershipError
└── ResourceError
├── ResourceNotFoundError
└── ForbiddenError
Configuration
Configure the assertion system programmatically:
from logguard import AssertionConfig, AssertionManager
# Switch to production mode (ASSERT becomes no-op)
AssertionManager.configure(
AssertionConfig(environment="production", enable_asserts=True)
)
# Custom failure handlers
def my_raise_handler(message, context, exception_class):
# Log to Sentry, then raise
sentry.capture_message(message, extra=context)
raise exception_class(message, context=context)
def my_log_handler(message, context, exception_class):
# Custom logging
metrics.increment("assertion_failures")
logger.warning(f"{exception_class.__name__}: {message}")
AssertionManager.set_failure_strategy(
raise_strategy=my_raise_handler,
log_strategy=my_log_handler,
)
# Reset to defaults (useful for testing)
AssertionManager.reset()
JSON Logging
For production environments, enable JSON logs for structured log aggregation:
from logguard import AppLogger
AppLogger.setup(json_logs=True, log_file="logs/app.json")
logger = AppLogger.get_logger(__name__)
logger.info("User logged in", extra={"user_id": 123})
logger.error("Database error", extra={"error_code": "DB_001"})
Requires: pip install py-logguard[json]
Note: Check out
examples/demo.pyfor a complete, interactive demonstration of all LogGuard features with Rich console output!
Run it with:
python examples/demo.py
API Reference
AppLogger - Logging Configuration
AppLogger is the main interface for logging. Configure it once and get loggers throughout your application.
Setup:
AppLogger.setup(
log_file="logs/app.log", # Path to log file
console_level="INFO", # Console output level
file_level="DEBUG", # File output level
json_logs=False, # Enable JSON formatting
max_bytes=5_000_000, # Max file size before rotation
backup_count=3, # Number of backups to keep
delay=True, # Delay file creation until first log
)
HandlerType enum: use instead of plain strings to select which handlers an operation targets:
| Member | Targets |
|---|---|
HandlerType.ALL |
Every handler (default) |
HandlerType.CONSOLE |
Console / RichHandler only |
HandlerType.FILE |
RotatingFileHandler only |
HandlerType.JSON |
JSON RotatingFileHandler only |
Methods:
get_logger(name: str | None = None): Get or create a logger instanceset_level(level, handler_type: HandlerType | str = HandlerType.ALL): Change log level on selected handlers at runtimeset_format(format_string, handler_type: HandlerType | str = HandlerType.ALL, datefmt=None): Change the format string on selected handlers; RichHandler and JsonFormatter instances are skipped automaticallysilence_noisy_libraries(modules: list[str] | None = None): Suppress third-party logsreset(): Reset configuration (useful for testing)
from logguard import AppLogger, HandlerType
AppLogger.setup(log_file="logs/app.log", console_level="INFO")
# Drop file handler to DEBUG without touching the console
AppLogger.set_level("DEBUG", HandlerType.FILE)
# Apply a compact format to file logs only
AppLogger.set_format("%(asctime)s | %(levelname)s | %(message)s", HandlerType.FILE)
Assertions - Environment-Aware Validation
Core Assertions:
| Function | Behavior |
|---|---|
CHECK(condition, message, **context) |
Always raises AssertFailure |
ASSERT(condition, message, **context) |
Raises in dev, ignored in prod |
ENSURE(condition, message, **context) |
Raises in dev, logs in prod |
VERIFY(condition, message, **context) |
Raises in dev, logs in prod |
Specialized Helpers:
| Function | Exception Type |
|---|---|
ASSERT_NOT_NULL(value, message) |
NullError |
ASSERT_NULL(value, message) |
NullError |
ASSERT_EQUALS(actual, expected, message) |
EqualsError |
ASSERT_GREATER(a, b, message) |
ComparisonError |
ASSERT_LESS(a, b, message) |
ComparisonError |
ASSERT_IN_RANGE(value, min, max, message) |
RangeError |
ASSERT_BETWEEN_EXCLUSIVE(value, min, max, message) |
RangeError |
ASSERT_TYPE(value, expected, message) |
TypeErrorAssert |
ASSERT_NOT_EMPTY(value, message) |
EmptyError |
ASSERT_IN(item, container, message) |
MembershipError |
Configuration Classes:
AssertionConfig(environment, enable_asserts)- Configuration dataclassAssertionManager- Central assertion engine withconfigure(),set_failure_strategy(),reset()
Exceptions - Semantic Error Hierarchy
All exceptions inherit from LogGuardError and include rich context information.
Properties:
message- Error descriptioncontext- Additional context data (dict).to_dict()- Serialize to dictionary for logging
Exception Types:
| Exception | Description |
|---|---|
LogGuardError |
Base for all exceptions |
ConfigurationError |
Invalid configuration |
MissingConfigError |
Required config key missing |
ValidationError |
Validation failures |
AssertFailure |
Base for assertion failures |
NullError |
Unexpected None value |
RangeError |
Value out of range |
TypeErrorAssert |
Wrong type |
EmptyError |
Unexpected empty value |
EqualsError |
Values not equal |
ComparisonError |
Comparison failed |
MembershipError |
Item not in container |
ResourceError |
Resource-related errors |
ResourceNotFoundError |
Resource not found |
ForbiddenError |
Permission denied |
Contributing
Contributions, issues and feature requests are welcome. Feel free to check the issues page.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Metadata
Release files for py-logguard 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| py_logguard-0.3.2.tar.gz | 38.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| py_logguard-0.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 60.1 kB
Release files / py_logguard-0.3.2.tar.gz
| Download URL | py_logguard-0.3.2.tar.gz |
|---|---|
| Size | 38.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a9293ff28da772831c8d33dcc4cafd4e1e80b9207b2fbde561f19041eaab7ad7
|
|
BLAKE2b-256 checksum How to use checksums |
a6ab6a4d4e6f2d3e8cb34bcd4ddb6e9524484a13655abfab3fb87fc6e8d70c43
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 21, 2026.
Transparency logRelease files / py_logguard-0.3.2-py3-none-any.whl
| Download URL | py_logguard-0.3.2-py3-none-any.whl |
|---|---|
| Size | 21.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4a8c4fa9fbe475145d47c040754603e11caca230763d9157408a200fc6d47381
|
|
BLAKE2b-256 checksum How to use checksums |
2f92105b3366432f4389165e4fb0eae4be2b95a1a650cbe49d0d960fdd9d7013
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 21, 2026.
Transparency log