Master Multi‑Environment Logging in Python with Loguru
This guide walks you through configuring Loguru for dev, test, and prod environments, adding dynamic log levels, colorized console output, file rotation, JSON serialization, remote extensions, and packaging the logger as a reusable Python module.
Goal
🧩 Multi‑environment configuration (dev, test, prod)
🔐 Dynamic log level setting
📁 File writing with automatic rotation (size/time)
💻 Colorful console output
📦 Structured logs in JSON format
🌐 Extensible to remote log sinks such as HTTP, Kafka, Sentry
1. Recommended directory layout
project_root/
├── config/
│ └── logging_config.py # logging configuration per environment
├── utils/
│ └── logger.py # wrapper around Loguru
├── logs/ # auto‑generated log files
│ └── app.log
├── main.py # example entry point
└── requirements.txt # dependencies2. Install dependencies
pip install loguru python-dotenv3. Complete code implementation
3.1 config/logging_config.py
# config/logging_config.py
import os
LOGGING_CONFIG = {
"dev": {
"level": "DEBUG",
"sink": "logs/app.log",
"rotation": "10 MB",
"retention": "7 days",
"colorize": True,
"serialize": False,
},
"test": {
"level": "INFO",
"sink": "logs/test_app.log",
"rotation": "5 MB",
"retention": "3 days",
"colorize": True,
"serialize": True, # JSON for easier analysis
},
"prod": {
"level": "WARNING",
"sink": "logs/prod_app.log",
"rotation": "1 day",
"retention": "30 days",
"colorize": False,
"serialize": True,
}
}
# Determine current environment (default to dev)
ENV = os.getenv("APP_ENV", "dev")
CONFIG = LOGGING_CONFIG[ENV]3.2 utils/logger.py
# utils/logger.py
from loguru import logger
import sys, os
from config.logging_config import CONFIG, ENV
def setup_logger():
# Ensure log directory exists
log_dir = os.path.dirname(CONFIG["sink"])
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# Remove default sink
logger.remove()
# Console sink (colorized based on environment)
logger.add(
sys.stderr,
level=CONFIG["level"],
colorize=CONFIG.get("colorize", True),
format="{time:YYYY-MM-DD HH:mm:ss}|{level}|{message}"
)
# File sink
logger.add(
CONFIG["sink"],
rotation=CONFIG["rotation"],
retention=CONFIG["retention"],
level="DEBUG", # write all levels to file
serialize=CONFIG.get("serialize", False),
encoding="utf-8"
)
logger.info(f"Logger initialized in {ENV.upper()} mode")
return logger
# Global logger instance
logger = setup_logger()3.3 main.py
# main.py
from utils.logger import logger
def main():
logger.debug("This is a DEBUG level log")
logger.info("This is an INFO level log")
logger.warning("This is a WARNING level log")
logger.error("This is an ERROR level log")
if __name__ == "__main__":
main()4. Running and switching environments
Set the APP_ENV environment variable to choose the logging behavior.
🟢 Development (dev) APP_ENV=dev python main.py Outputs all logs to the terminal and logs/app.log with colored output.
🟡 Testing (test) APP_ENV=test python main.py Writes JSON logs to logs/test_app.log; console shows INFO and above.
🔴 Production (prod) APP_ENV=prod python main.py Writes JSON logs to logs/prod_app.log; only WARNING and above are recorded, without colors, suitable for log aggregation systems.
5. Example of a serialized JSON log (when serialize=True )
{
"elapsed": "0:00:00.001234",
"exception": null,
"extra": {},
"file": {"name": "main.py", "path": "/path/to/main.py"},
"function": "main",
"level": {"icon": "⚠️", "name": "WARNING", "no": 30},
"line": 7,
"message": "This is a WARNING level log",
"module": "main",
"thread": {"id": 12345, "name": "MainThread"},
"time": "2025-04-05T10:34:56.123456Z"
}6. Optional advanced features
7. Packaging for reuse (optional)
pip install setuptools wheel # Build the distribution
python setup.py sdist bdist_wheel # Upload to PyPI or a private repository
twine upload dist/*8. Conclusion
The article demonstrates how to build a flexible, multi‑environment logging solution with Loguru, covering configuration, code implementation, runtime switching, JSON serialization, and optional packaging for team-wide reuse.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
