Reputation: 345
I has the python logger which is configured by file.
[loggers]
keys=root
[handlers]
keys=consoleHandler, errorHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler, errorHandler
[handler_consoleHandler]
class=FileHandler
level=DEBUG
formatter=simpleFormatter
args=('%(filename)s',)
[handler_errorHandler]
class=FileHandler
level=ERROR
formatter=simpleFormatter
args=('error.log',)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
datefmt=
So, I call the configuration file like this:
logging.config.fileConfig('logging.cfg', defaults={'filename': 'may2020.log'})
But I want to change filename monthly. For example, now filename is set to may2020.log
, and it the beginning of the next month I want to rename it as june2020.log
. How can I dynamically change the filename without restarting the application?
Upvotes: 0
Views: 1006
Reputation: 141
To dynamically change the log file is possible. In my example I have one codebase but 4 different processes running, each starting from a different 'main' file. Since all of them run on a day and some may run at overlapping times, i do not want the logs to be mixed together. Such a mixed log will be useless for debugging issues. There are several modules that must log to the file as directed to by the 'main'.
in file logger_config.py:
import logging
from logging.handlers import TimedRotatingFileHandler
import sys
FORMATTER = logging.Formatter("%(asctime)s %(levelname)s %(filename)s -> %(funcName)s : line %(lineno)s, %(message)s",
"%Y-%m-%d %H:%M:%S")
def get_console_handler():
console_handler = logging.StreamHandler(sys.stdout)
console_handler.setFormatter(FORMATTER)
return console_handler
def get_file_handler(logger_name):
file = f'logs/{logger_name}.log'
file_handler = TimedRotatingFileHandler(file, when='midnight', backupCount=7)
file_handler.setFormatter(FORMATTER)
return file_handler
def get_logger(logger_name):
logger = logging.getLogger(logger_name)
logger.setLevel(logging.DEBUG)
logger.addHandler(get_console_handler())
logger.addHandler(get_file_handler(logger_name))
# with this pattern, it's rarely necessary to propagate the error up to parent
logger.propagate = False
return logger
def switch_log_file(log_obj, new_filename):
for handler in log_obj.handlers[:]:
if isinstance(handler, logging.FileHandler):
log_obj.removeHandler(handler)
log_obj.addHandler(get_file_handler(new_filename))
log = get_logger('main_') # this is a default name to initialise with and then switch name as needed.
in my main file e.g. main_something.py
from logger_config import log, switch_log_file
import other_stuff
if __name__ == '__main__':
switch_log_file(log, 'something')
log.debug('\n Start')
# carry on and do stuff
In each module that is called by main or any other module:
from logger_config import log
def some_method(in_str, subs):
log.debug('Start')
...
return True
All my logs go to the subdirectory 'logs' and i then have log files that identify with the main process.
Upvotes: 0
Reputation: 38
Late answer but for anyone interested:
There is a handler for this exact purpose: logging.handlers.TimedRotatingFileHandler
Upvotes: 1
Reputation: 16
Quick and dirty:
from datetime import datetime
now = datetime.now()
logging.config.fileConfig('logging.cfg', defaults={'filename': f'{now.strftime("%B").lower()}{now.year}.log'})
This will work on Python 3.6+
Upvotes: 0