Search code examples
pythonpython-3.xpython-logginguvicorn

What does "()" do in python log config


I have seen a python dict log config in uvicorn's source code.

In that, they have defined formatters as

{
    "default": {
        "()": "uvicorn.logging.DefaultFormatter",
        "fmt": "%(levelprefix)s %(asctime)s %(message)s",
        "datefmt": "%Y-%m-%d %H:%M:%S",

    },
    "access": {
        "()": "uvicorn.logging.AccessFormatter",
        "fmt": '%(levelprefix)s %(asctime)s :: %(client_addr)s - "%(request_line)s" %(status_code)s',
        "use_colors": True
    },
}

also, we can see, they defined an empty logger ( not sure what should I call it) as,

"": {"handlers": ["default"], "level": "INFO"},
^^^^ - see, Empty key

So, here is my questions,

  1. What does the "()" do in formatters section of python logger?
  2. What does the "" do in loggers section python logger?

Solution

  • This dictionary is used to configure logging with logging.config.dictConfig().

    The "()" key indicates that custom instantiation is required [source]:

    In all cases below where a ‘configuring dict’ is mentioned, it will be checked for the special '()' key to see if a custom instantiation is required. If so, the mechanism described in User-defined objects below is used to create an instance; otherwise, the context is used to determine what to instantiate.

    In the case of the formatter config in the OP's question, the "()" indicates that those classes should be used to instantiate a Formatter.

    I do not see the empty string in the loggers section of the dictionary, but here are the related docs:

    loggers - the corresponding value will be a dict in which each key is a logger name and each value is a dict describing how to configure the corresponding Logger instance.

    The configuring dict is searched for the following keys:

    • level (optional). The level of the logger.
    • propagate (optional). The propagation setting of the logger.
    • filters (optional). A list of ids of the filters for this logger.
    • handlers (optional). A list of ids of the handlers for this logger.

    The specified loggers will be configured according to the level, propagation, filters and handlers specified.

    So a "" key in the loggers dictionary would instantiate a logger with the name "", like logging.getLogger("").


    One might use a custom logging formatter for a variety of reasons. uvicorn uses a custom formatter to log different levels in different colors. The Python Logging Cookbook has an example of using a custom formatter to use UTC times instead of local times in logging messages.

    import logging
    import time
    
    class UTCFormatter(logging.Formatter):
        converter = time.gmtime
    
    LOGGING = {
        ...
        'formatters': {
            'utc': {
                '()': UTCFormatter,
                'format': '%(asctime)s %(message)s',
            },
            'local': {
                'format': '%(asctime)s %(message)s',
            }
        },
        ...
    }
    
    if __name__ == '__main__':
        logging.config.dictConfig(LOGGING)
        logging.warning('The local time is %s', time.asctime())
    

    Here is the output. Note that in the first line, UTC time is used instead of local time, because the UTCFormatter is used.

    2015-10-17 12:53:29,501 The local time is Sat Oct 17 13:53:29 2015
    2015-10-17 13:53:29,501 The local time is Sat Oct 17 13:53:29 2015