Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get current (or basic) python logging configuration as a dictionary

I am using the Python standard logging configuration, combined with yaml to load a config file with the dictConfig() function:

import logging
import yaml
 
with open('logging.yaml','r') as f:
    logConfig = yaml.safe_load(f.read())
logging.config.dictConfig(logConfig)

Since an incremental logging configuration in python limits the capabilities, every logging file has to contain a minimum amount of information, something like this:

version: 1
formatters:
    simple:
        format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"

handlers:
    console:
        class: logging.StreamHandler
        level: DEBUG
        formatter: simple

loggers:
    my_module:
        level: ERROR

root:
    level: INFO
    handlers: [console] 

Which either forces one to learn this by heart, store it somewhere, or look it up each time. Since neither of these really work for me, I would like to find a way to generate it. This brings me to the question:

Is there a way to get the current (or basic) logging config as a dictionary?

This would make it easy to make an initial config file by running the following code once, and just remove/edit what you want:

import logging
import yaml

logConfig = logging.get_current_config_as_a_dictionary()
with open('logging.yaml','w') as f:
    f.write(yaml.dump(logConfig))

Yaml is just my personal preference of course, the same question could be posted for something like JSON.

like image 502
user3053216 Avatar asked Oct 28 '18 18:10

user3053216


Video Answer


2 Answers

I'm not sure if there's a clean way do to this through any public logging function. Looking through the package CPython source, the defaults aren't set aside and neatly defined in any structure (such as a dict). Instead, they're hardcoded into the function logging.basicConfig. Specifically, this function contains some common "default" setup keywords, but unfortunately for your purposes, these are hardcoded into the function. For example:

style = kwargs.pop("style", '%')

This uses the root logger (which itself is root = RootLogger(logging.WARNING)) and adds some config to it.

One way to work with that, which is really not ideal, would be to look at the "before and after" config tied to logging.root before and after you call logging.basicConfig()*. For example:

>>> root = logging.root
>>> root.handlers
[]
>>> logging.basicConfig()
>>> root.handlers
[<StreamHandler <stderr> (NOTSET)>]

Lastly, I would mention that the default style comes from:

logging._STYLES['%']

which works out to %(levelname)s:%(name)s:%(message)s.

*If you call this function with no arguments, there is really not a whole lot done; the main change is adding a StreamHandler (stdout) to the root logger and then adding a Formatter to that.

like image 51
Brad Solomon Avatar answered Nov 09 '22 03:11

Brad Solomon


I don't see a complete solution for you, but the logging_tree package looks like a step in the right direction. If you look at its source code, you may be able to change its output to match the dictionary you're looking for.

Here's the output it currently generates, from its home page:

>>> logging.getLogger('a')
>>> logging.getLogger('a.b').setLevel(logging.DEBUG)
>>> logging.getLogger('x.c')
>>> from logging_tree import printout
>>> printout()
<--""
   Level WARNING
   |
   o<--"a"
   |   Level NOTSET so inherits level WARNING
   |   |
   |   o<--"a.b"
   |       Level DEBUG
   |
   o<--[x]
       |
       o<--"x.c"
           Level NOTSET so inherits level WARNING
like image 29
Don Kirkby Avatar answered Nov 09 '22 02:11

Don Kirkby