3. Logger Configuration
For operating this project reliably, I need a robust logging system. So I decided the Loguru
library for its simplicity and powerful features. The configuration was customized to meet the following requirements:
- Custom Log Formatting
Example:
2025-06-26 23:09:24 | INFO | main :lifespan :16 - Starting up the application...
- Persistent Log Files
- Save logs using filenames that include the current date.
- Retain logs for 7 days only.
- Integration with FastAPI and Uvicorn Logs
- Ensure logs from
FastAPI
,Uvicorn
, andStarlette
are captured uniformly
- Ensure logs from
1. Pseudocode Summary
IF LogConfigurator not configured:
- Create log directory
- Remove default handlers
- Add colored console logger
- Add rotating file logger
- Setup InterceptHandler for uvicorn/starlette/fastapi loggers
- Mark as configured
2. How I Configured the Logger
- To satisfy the logging requirements mentioned above, I built a singleton
LogConfigurator
usingLoguru
, which includes:
2.1 Installing loguru
- First, install
Loguru
usinguv
:uv pip install loguru
2.2 Singleton Pattern
- I wanted to ensure that the logger is configured only once, even if multiple modules try to initialize it. The class uses a standard
__new__
pattern to maintain a single instance.def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance
2.3 Log File Management
- Each log file is automatically named using the current date and saved under
/backend/logs
. I use Loguru’s built-in rotation and retention to:- Create a new file every day at midnight
- Retain logs only for 7 days
- Avoid manual cleanup
logger.add( str(self.log_file), rotation="00:00", # Daily rotation retention="7 days", # Keep logs for 7 days encoding="utf-8", level="INFO", ... )
2.4 Console Output with Colors
- Loguru’s
colorize=True
option lets me apply colors to console logs, improving readability during development.logger.add( sys.stdout, level="INFO", colorize=True, format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name: <20}</cyan>:<cyan>{function: <15}</cyan>:<cyan>{line: <4}</cyan> - <level>{message}</level>", )
2.5 Intercepting FastAPI/Uvicorn Logs
- By default, FastAPI and Uvicorn use the built-in logging module. To unify all logs under Loguru, I wrote a custom
InterceptHandler
which:- Captures standard logging logs
- Redirects them to Loguru with correct context (function name, line number, etc.)
logging.basicConfig( handlers=[InterceptHandler()], level=logging.INFO, force=True )
- I explicitly intercept common loggers:
loggers_to_intercept = [ "uvicorn", "uvicorn.access", "uvicorn.error", "fastapi", "starlette", "starlette.routing", ]
2.6 Execution Outputs
This setup ensures that all logs—whether they come from my own modules or external frameworks—are managed consistently, well-formatted, and stored efficiently.