The all-in-one structured logging solution for modern Python applications.
Built on top of structlog. Designed for FastAPI, Flask, Django, and production scripts.
Features • Installation • Quick Start • Configuration • Integrations
Lynx Logger bridges the gap between simple print debugging and complex enterprise logging systems.
- ✨ Zero-Config Start: Get beautiful logs with a single line of code.
- 📦 Structured & JSON: Native JSON support for ELK Stack, Datadog, or Loki.
- 🔍 Context-Aware: Automatic tracing of
request_id,user_id, and trace contexts across your app. - 🛡 Smart Filtering: Built-in filters for PII (GDPR compliance), log levels, and sources.
- 📂 File Rotation: Robust file handling with size limits and backups out of the box.
- 🔌 Framework Ready: Middleware included for FastAPI, Flask, and Django.
pip install lynx-loggerOptional Dependencies:
| Extra | Use Case |
|---|---|
lynx-logger[web] |
Optimized for web frameworks (FastAPI, Starlette, Flask, Django) |
lynx-logger[all] |
Installs all dependencies including dev tools |
Perfect for local development with readable, colored output.
from lynx_logger import setup_logger
logger = setup_logger("my_service")
logger.info("Service started", version="1.0.0")
logger.warning("Cache miss", key="user:123", latency_ms=45)
# Output: 2025-02-05 [INFO] my_service: Service started version=1.0.0Optimized for log aggregators.
logger = setup_logger(
name="payment_service",
level="INFO",
format="json", # Outputs strict JSON
log_to_file=True,
logs_dir="./logs"
)
logger.info("Transaction processed", amount=500, currency="USD", user_id=42)
# Output: {"timestamp": "...", "level": "info", "event": "Transaction processed", "amount": 500, ...}| Format | Example Output | Best For |
|---|---|---|
| Console | [INFO] app: Server started port=8000 (Colored) |
Local Development |
| JSON | {"ts": "...", "level": "info", "msg": "Server started"} |
Production / ELK |
| Key-Value | level=info event='Server started' port=8000 |
Legacy Systems |
Stop passing user_id as an argument to every function. Lynx Logger handles context for you.
from lynx_logger import RequestContext
# Automatically injects request_id into every log within this block
with RequestContext(request_id="req_123", user_id="user_456"):
logger.info("Querying database")
# Log includes: request_id="req_123" user_id="user_456"# Create a logger instance bound to specific data
job_logger = logger.bind(job_id="job_999")
job_logger.info("Job started")
job_logger.info("Job finished")
# Both logs will contain job_id="job_999"Prevent log flooding when errors occur in a loop.
from lynx_logger import ThrottleFilter
# Allow max 10 identical messages per minute
throttle = ThrottleFilter(max_repeats=10, time_window=60)Automatically mask or exclude sensitive data.
from lynx_logger import ContentFilter, LogConfig, LynxLogger
config = LogConfig(
name="app",
filters=ContentFilter(
exclude_patterns=["password", "secret_key", "auth_token"],
case_sensitive=False
)
)
logger = LynxLogger(config)Lynx Logger follows the 12-Factor App methodology and can be configured via Environment Variables.
| Environment Variable | Default | Description |
|---|---|---|
LOG_NAME |
root |
Service name |
LOG_LEVEL |
INFO |
Logging level (DEBUG, INFO, ERROR) |
LOG_FORMAT |
console |
Output format: console, json, keyvalue |
LOG_TO_FILE |
false |
Enable file logging |
LOG_DIR |
./logs |
Directory for log files |
Or via Python Dictionary:
config = LogConfig.from_dict({
"name": "worker",
"level": "DEBUG",
"file": {
"filename": "worker.log",
"max_size": "50MB",
"backup_count": 5
}
})from fastapi import FastAPI, Request
from lynx_logger import setup_logger, RequestContext
import uuid
app = FastAPI()
logger = setup_logger("api", format="json")
@app.middleware("http")
async def log_middleware(request: Request, call_next):
req_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
# Context is automatically cleared after the request finishes
with RequestContext(request_id=req_id, path=request.url.path):
logger.info("Request started")
response = await call_next(request)
logger.info("Request finished", status=response.status_code)
return responseContributions are welcome!
-
Fork the repository.
-
Create your feature branch.
-
Commit your changes.
-
Open a Pull Request.
Please open an Issue for any bugs or feature requests.
This project is licensed under the MIT License.
Developed with ❤️ by FlacSy