As @Senthil Kumaran stated, this kind of logic is best put at the application level. Here's a full working example that sets up a logger that prints to stdout and writes to file. At application start up, if an existing log is found with the same name, it will be rotated out of the way in to a directory named 'old'. The RotatingFileHandler then handles rotating live logs when their size exceeds 512 bytes.
import logging import logging.handlers as handlers from pathlib import Path from typing import List def configure_logger(): file_handler = _get_file_handler() log_handlers: List[logging.Handler] = [logging.StreamHandler(), file_handler] logging.basicConfig( level="INFO", format="[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s", handlers=log_handlers, ) def _get_file_handler() -> handlers.RotatingFileHandler: log_path_str = "logs/my_app.log" log_path = Path(log_path_str) _rotate_existing_log(log_path) log_path.parent.mkdir(parents=True, exist_ok=True) return handlers.RotatingFileHandler( log_path, maxBytes=512, backupCount=5, # don't append to existing file, instead create a new mode="w", ) def _rotate_existing_log(log_path: Path): """ If log file already exists, rotate it out of the way into an 'old' directory :param log_path: :return: """ if log_path.exists(): old_log_paths = log_path.parent / "old" old_log_paths.mkdir(parents=True, exist_ok=True) i = 1 old_log_name = old_log_paths / (log_path.name + f".{i}") while old_log_name.exists(): i += 1 old_log_name = old_log_paths / (log_path.name + f".{i}") log_path.rename(old_log_name) if __name__ == "__main__": configure_logger() logger = logging.getLogger(__name__) logger.info("hello world")
The effect of running this on my system a few times gave the following directory and file structure:
C:\USERS\PYCHARMPROJECTS\SCRATCH\LOGS | my_app.log | \---old my_app.log.1 my_app.log.2 my_app.log.3 my_app.log.4
