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