4

I am using the following dictConfig for a logger. However, I am unable to modify the logging level at runtime.

#contents of log_config.json

{
    "version": 1,
    "disable_existing_loggers": false,
    "formatters": {
        "simple": {
            "format": "%(asctime)s - %(name)-12s - %(levelname)-8s - %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S"
        },
        "detailed": {
            "format": "%(asctime)s %(name)-12s %(module)-17s line:%(lineno)-4d %(levelname)-8s %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S"
        }
    },

    "handlers": {
        "console": {
            "class": "logging.StreamHandler",
            "level": "INFO",
            "formatter": "simple",
            "stream": "ext://sys.stdout"
        },

        "info_file_handler": {
            "class": "logging.handlers.TimedRotatingFileHandler",
            "level": "INFO",
            "formatter": "detailed",
            "filename": "info.log",
            "when": "midnight",
            "backupCount": 7,
            "encoding": "utf8"
        },

        "error_file_handler": {
            "class": "logging.handlers.TimedRotatingFileHandler",
            "level": "ERROR",
            "formatter": "detailed",
            "filename": "errors.log",
            "when": "midnight",
            "backupCount": 7,
            "encoding": "utf8"
        }
    },

    "loggers": {
        "": {
            "level": "ERROR",
            "handlers": ["console"],
            "propagate": "no"
        }
    },

    "root": {
        "level": "NOTSET",
        "handlers": ["console", "info_file_handler", "error_file_handler"]
    }
}

I then get the logger and set the level using:

with open('/path/to/log_config.json', 'r') as fd:
    cfg = json.load(fd)

logging.config.dictConfig(cfg)
logger = logging.getLogger(__name__)
logger.setLevel(10)

But, because the logger was created using the dictConfig I am not able to override the levels. I would like to build a UI tool which has an option menu to adjust the logging levels at runtime without having to crack open code or the json file to make adjustments. I am able to adjust the level higher, but for some reason it will not let the level go lower...

What I would like to do is set the info_file and console handlers to INFO (20) in the config, and then have the option to change them to DEBUG (10) at runtime. Any ideas?

Bhargav Rao
  • 41,091
  • 27
  • 112
  • 129
pipeTD
  • 41
  • 2

2 Answers2

1

I had a similar problem, and just figured it out.

In my case I only wanted to change the level for the "console" handler, but you can easily extend this to all handlers and try it out:

logger = logging.getLogger(__name__)
for handler in logger.handlers:
    if handler.get_name() == 'console':
        handler.setLevel(logging.DEBUG)

(note, I copied your __name__, but for me I'm using an actual string to name the logger - just in case that matters)

Starman
  • 154
  • 9
  • 2
    Not working for me and when I look at logger.handlers I'm getting []. – Jason Templeman Jul 19 '18 at 17:36
  • Same here. I configured and initalized Logger instance in a similar fashion as the question's Author, applied snippet provided by @Starman and I am getting similar output - looks like the all attributes of logger are missing (handlers = [], level = 0 etc.). Perhaps it is a library issue? On the other hand logger performs its' task decribed in initial config correctly (e.g. write to a declared file etc.)so I am little confused... – Marek Bocian Jul 23 '20 at 15:46
  • I had the same issue, and these finally clarified for me that I wasn't setting the root logger correctly- https://stackoverflow.com/questions/47422689/python-logging-how-to-inherit-root-logger-level-handler and https://stackoverflow.com/questions/24719421/logging-handlers-empty-why-logging-timeroatingfilehandler-doesnt-work?noredirect=1&lq=1 @MarekBocian – JJ101 Oct 06 '20 at 02:25
1

I was looking for a dict config and I found your question. I followed your exact code and I also couldn't change the log level then I found this answer. And instead of __name__ using @Tjorriemorrie 's third solution returned correct logger.handlers. And I combined with @Starman ' s answer... Now I can change the logging level wherever I want and whenever I want.

logger = logging.getLogger()
for handler in logger.handlers:
    if handler.get_name() == 'console':
        handler.setLevel(logging.DEBUG)

PS: Thank you for your code snippet! It helped me a lot.

MehmedB
  • 492
  • 5
  • 23
  • Nice work. \n. So by removing the `_name_ ` which OP was specifying, it just returns the correct logger? Does that work for OP? As I mentioned in my answer, I myself don't use `_name_` there, but OP seemed to want a logger named after his filename, I guess. – Starman Oct 07 '20 at 16:03