How to set new filename for python logger which is file-configured?

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

Answers (3)

Getafix
Getafix

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

SDAO
SDAO

Reputation: 38

Late answer but for anyone interested:

There is a handler for this exact purpose: logging.handlers.TimedRotatingFileHandler

Upvotes: 1

rfr
rfr

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

Related Questions